agora inbox for pgsql-bugs@postgresql.org  
help / color / mirror / Atom feed
BUG #19369: Not documented that io_uring on kernel versions between 5.1 and below 5.6 does not work
18+ messages / 6 participants
[nested] [flat]

* BUG #19369: Not documented that io_uring on kernel versions between 5.1 and below 5.6 does not work
@ 2026-01-02 22:46  PG Bug reporting form <noreply@postgresql.org>
  0 siblings, 1 reply; 18+ messages in thread

From: PG Bug reporting form @ 2026-01-02 22:46 UTC (permalink / raw)
  To: pgsql-bugs@lists.postgresql.org; +Cc: evsi@amazon.com

The following bug has been logged on the website:

Bug reference:      19369
Logged by:          Evan Si
Email address:      evsi@amazon.com
PostgreSQL version: 18.1
Operating system:   Amazon Linux 2
Description:        

Hello,

The documentation doesn't explicitly state a minimum kernel version for
io_uring, but in src/backend/storage/aio/README.md, it claims that:

> io_method=io_uring is available on Linux 5.1+.

Attempting to set io_method to io_uring on versions without io_uring at all
(below 5.1) causes the server to graciously report that "[the k]ernel does
not support io_uring".
But setting io_uring on kernel versions between 5.1 and 5.6 sees the server
start but connections failing with EINVAL.

```
[ec2-user@ip-172-31-56-49 postgres]$ psql postgres
psql: error: connection to server on socket "/tmp/.s.PGSQL.5432" failed:
FATAL:  could not read blocks 0..0 in file "global/1260": Invalid argument
```

It seems like the implementation in postgres leverages non-vectored I/O
(i.e. io_uring_prep_read and io_uring_prep_write) in
src/backend/storage/aio/method_io_uring.c.

But, these opcodes aren't actually available until kernel 5.6
(https://github.com/axboe/liburing/issues/44),
(https://man7.org/linux/man-pages/man2/io_uring_enter.2.html - under
IORING_OP_READ, IORING_OP_WRITE).

It seems kernel 5.4 LTS ended last month, but this seems worth clarifying, I
think.

--

Precise reproduction example:

OS details
```
[ec2-user@ip-172-31-56-49 postgres]$ uname -a
Linux ip-172-31-56-49.us-west-2.compute.internal
5.4.301-221.450.amzn2.x86_64 #1 SMP Tue Nov 18 16:40:04 UTC 2025 x86_64
x86_64 x86_64 GNU/Linux
```

Build postgres with liburing 2.8, set postgresql.conf with
io_method=io_uring, log_min_messages = debug3.

Postgres starts without complaint, but trying to connect will fail:

```
[ec2-user@ip-172-31-56-49 postgres]$ psql postgres
psql: error: connection to server on socket "/tmp/.s.PGSQL.5432" failed:
FATAL:  could not read blocks 0..0 in file "global/1260": Invalid argument
```
Inside logfile:
```
2026-01-02 22:35:43.862 UTC [8517] DEBUG:  io 6400      |op invalid|target
invalid|state HANDED_OUT      : adding cb #1, id
2/aio_shared_buffer_readv_cb
2026-01-02 22:35:43.862 UTC [8517] DEBUG:  io 6400      |op invalid|target
smgr|state HANDED_OUT      : adding cb #2, id 1/aio_md_readv_cb
2026-01-02 22:35:43.863 UTC [8517] DEBUG:  io 6400      |op readv|target
smgr|state DEFINED         : calling cb #1
2/aio_shared_buffer_readv_cb->stage(0)
2026-01-02 22:35:43.863 UTC [8517] DEBUG:  io 6400      |op readv|target
smgr|state STAGED          : staged (synchronous: 0, in_batch: 1)
2026-01-02 22:35:43.863 UTC [8517] DEBUG:  io 6400      |op readv|target
smgr|state SUBMITTED       : wait_one io_gen: 3, ref_gen: 3, cycle 0
2026-01-02 22:35:43.863 UTC [8517] LOG:  could not read blocks 0..0 in file
"global/1262": Invalid argument
2026-01-02 22:35:43.863 UTC [8517] DEBUG:  io 6400      |op readv|target
smgr|state COMPLETED_IO    : after shared completion: distilled result:
(status ERROR, id 1, error_data: 22, result 0), raw_result: -22
2026-01-02 22:35:43.863 UTC [8517] DEBUG:  io 6400      |op readv|target
smgr|state COMPLETED_SHARED: after local completion: result: (status ERROR,
id 1, error_data 22, result 0), raw_result: -22
2026-01-02 22:35:43.863 UTC [8517] DEBUG:  drained 1/1, now expecting 0
2026-01-02 22:35:43.863 UTC [8517] DEBUG:  io 6400      |op invalid|target
invalid|state IDLE            : wait_one io_gen: 4, ref_gen: 3, cycle 0
2026-01-02 22:35:43.863 UTC [8517] DEBUG:  wait_one with 0 sleeps
2026-01-02 22:35:43.863 UTC [8517] ERROR:  could not read blocks 0..0 in
file "global/1262": Invalid argument
2026-01-02 22:35:44.057 UTC [8512] DEBUG:  assigned pm child slot 1 for
backend
2026-01-02 22:35:44.058 UTC [8512] DEBUG:  forked new client backend,
pid=8521 socket=151
2026-01-02 22:35:44.058 UTC [8521] DEBUG:  InitPostgres
2026-01-02 22:35:44.059 UTC [8521] DEBUG:  io 0         |op invalid|target
invalid|state HANDED_OUT      : adding cb #1, id
2/aio_shared_buffer_readv_cb
2026-01-02 22:35:44.059 UTC [8521] DEBUG:  io 0         |op invalid|target
smgr|state HANDED_OUT      : adding cb #2, id 1/aio_md_readv_cb
2026-01-02 22:35:44.059 UTC [8521] DEBUG:  io 0         |op readv|target
smgr|state DEFINED         : calling cb #1
2/aio_shared_buffer_readv_cb->stage(0)
2026-01-02 22:35:44.059 UTC [8521] DEBUG:  io 0         |op readv|target
smgr|state STAGED          : staged (synchronous: 0, in_batch: 1)
2026-01-02 22:35:44.059 UTC [8521] DEBUG:  io 0         |op readv|target
smgr|state SUBMITTED       : wait_one io_gen: 1, ref_gen: 1, cycle 0
2026-01-02 22:35:44.059 UTC [8521] LOG:  could not read blocks 0..0 in file
"global/1260": Invalid argument
2026-01-02 22:35:44.059 UTC [8521] DEBUG:  io 0         |op readv|target
smgr|state COMPLETED_IO    : after shared completion: distilled result:
(status ERROR, id 1, error_data: 22, result 0), raw_result: -22
2026-01-02 22:35:44.059 UTC [8521] DEBUG:  io 0         |op readv|target
smgr|state COMPLETED_SHARED: after local completion: result: (status ERROR,
id 1, error_data 22, result 0), raw_result: -22
2026-01-02 22:35:44.059 UTC [8521] DEBUG:  drained 1/1, now expecting 0
2026-01-02 22:35:44.059 UTC [8521] DEBUG:  io 0         |op invalid|target
invalid|state IDLE            : wait_one io_gen: 2, ref_gen: 1, cycle 0
2026-01-02 22:35:44.059 UTC [8521] DEBUG:  wait_one with 0 sleeps
2026-01-02 22:35:44.059 UTC [8521] FATAL:  could not read blocks 0..0 in
file "global/1260": Invalid argument
2026-01-02 22:35:44.059 UTC [8521] DEBUG:  shmem_exit(1): 5
before_shmem_exit callbacks to make
2026-01-02 22:35:44.059 UTC [8521] DEBUG:  shmem_exit(1): 7 on_shmem_exit
callbacks to make
2026-01-02 22:35:44.059 UTC [8521] DEBUG:  proc_exit(1): 2 callbacks to make
2026-01-02 22:35:44.059 UTC [8521] DEBUG:  exit(1)
2026-01-02 22:35:44.059 UTC [8521] DEBUG:  shmem_exit(-1): 0
before_shmem_exit callbacks to make
2026-01-02 22:35:44.059 UTC [8521] DEBUG:  shmem_exit(-1): 0 on_shmem_exit
callbacks to make
2026-01-02 22:35:44.059 UTC [8521] DEBUG:  proc_exit(-1): 0 callbacks to
make
2026-01-02 22:35:44.060 UTC [8512] DEBUG:  releasing pm child slot 1
2026-01-02 22:35:44.060 UTC [8512] DEBUG:  client backend (PID 8521) exited
with exit code 1
2026-01-02 22:35:44.863 UTC [8517] DEBUG:  io 6400      |op invalid|target
invalid|state HANDED_OUT      : adding cb #1, id
2/aio_shared_buffer_readv_cb
2026-01-02 22:35:44.863 UTC [8517] DEBUG:  io 6400      |op invalid|target
smgr|state HANDED_OUT      : adding cb #2, id 1/aio_md_readv_cb
2026-01-02 22:35:44.863 UTC [8517] DEBUG:  io 6400      |op readv|target
smgr|state DEFINED         : calling cb #1
2/aio_shared_buffer_readv_cb->stage(0)
2026-01-02 22:35:44.863 UTC [8517] DEBUG:  io 6400      |op readv|target
smgr|state STAGED          : staged (synchronous: 0, in_batch: 1)
2026-01-02 22:35:44.863 UTC [8517] DEBUG:  io 6400      |op readv|target
smgr|state SUBMITTED       : wait_one io_gen: 4, ref_gen: 4, cycle 0
2026-01-02 22:35:44.863 UTC [8517] LOG:  could not read blocks 0..0 in file
"global/1262": Invalid argument
2026-01-02 22:35:44.863 UTC [8517] DEBUG:  io 6400      |op readv|target
smgr|state COMPLETED_IO    : after shared completion: distilled result:
(status ERROR, id 1, error_data: 22, result 0), raw_result: -22
2026-01-02 22:35:44.863 UTC [8517] DEBUG:  io 6400      |op readv|target
smgr|state COMPLETED_SHARED: after local completion: result: (status ERROR,
id 1, error_data 22, result 0), raw_result: -22
2026-01-02 22:35:44.863 UTC [8517] DEBUG:  drained 1/1, now expecting 0
2026-01-02 22:35:44.863 UTC [8517] DEBUG:  io 6400      |op invalid|target
invalid|state IDLE            : wait_one io_gen: 5, ref_gen: 4, cycle 0
2026-01-02 22:35:44.863 UTC [8517] DEBUG:  wait_one with 0 sleeps
2026-01-02 22:35:44.863 UTC [8517] ERROR:  could not read blocks 0..0 in
file "global/1262": Invalid argument
```



^ permalink  raw  reply  [nested|flat] 18+ messages in thread

* Re: BUG #19369: Not documented that io_uring on kernel versions between 5.1 and below 5.6 does not work
@ 2026-01-08 04:15  surya poondla <suryapoondla4@gmail.com>
  parent: PG Bug reporting form <noreply@postgresql.org>
  0 siblings, 1 reply; 18+ messages in thread

From: surya poondla @ 2026-01-08 04:15 UTC (permalink / raw)
  To: evsi@amazon.com; pgsql-bugs@lists.postgresql.org

Hi Evsi,

I created a new Ubuntu server and am able to reproduce the same behavior
you reported for Postgres 18.1 on aarch64 architecture.

surya@surya:~/pgdata18/log$ uname -r
5.4.0-216-generic
surya@surya:~/pgdata18/log$ uname -a
Linux surya 5.4.0-216-generic #236-Ubuntu SMP Fri Apr 11 19:55:34 UTC 2025
aarch64 aarch64 aarch64 GNU/Linux

I did some testing and see the below
In the postgresql.conf if I put
io_method = 'worker' or io_method = 'sync', postgres is able to restart
with no errors.
But if io_method = 'io_uring' then I see the below on my console

surya@surya:~/postgresql-18.1$ vim ~/pgdata18/postgresql.conf
surya@surya:~/postgresql-18.1$ ~/pg18/bin/pg_ctl -D ~/pgdata18 restart
waiting for server to shut down....2026-01-08 04:06:07.081 UTC [44973]
DEBUG:  logger shutting down
2026-01-08 04:06:07.081 UTC [44973] DEBUG:  shmem_exit(0): 0
before_shmem_exit callbacks to make
2026-01-08 04:06:07.081 UTC [44973] DEBUG:  shmem_exit(0): 0 on_shmem_exit
callbacks to make
2026-01-08 04:06:07.081 UTC [44973] DEBUG:  proc_exit(0): 0 callbacks to
make
2026-01-08 04:06:07.081 UTC [44973] DEBUG:  exit(0)
2026-01-08 04:06:07.081 UTC [44973] DEBUG:  shmem_exit(-1): 0
before_shmem_exit callbacks to make
2026-01-08 04:06:07.081 UTC [44973] DEBUG:  shmem_exit(-1): 0 on_shmem_exit
callbacks to make
2026-01-08 04:06:07.081 UTC [44973] DEBUG:  proc_exit(-1): 0 callbacks to
make
 done
server stopped
waiting for server to start....2026-01-08 04:06:07.172 GMT [44988] LOG:
 invalid value for parameter "io_method": "io_uring"
2026-01-08 04:06:07.172 GMT [44988] HINT:  Available values: sync, worker.
2026-01-08 04:06:07.172 UTC [44988] FATAL:  configuration file
"/home/surya/pgdata18/postgresql.conf" contains errors
2026-01-08 04:06:07.172 UTC [44988] DEBUG:  shmem_exit(1): 0
before_shmem_exit callbacks to make
2026-01-08 04:06:07.172 UTC [44988] DEBUG:  shmem_exit(1): 0 on_shmem_exit
callbacks to make
2026-01-08 04:06:07.172 UTC [44988] DEBUG:  proc_exit(1): 0 callbacks to
make
2026-01-08 04:06:07.172 UTC [44988] DEBUG:  exit(1)
 stopped waiting
pg_ctl: could not start server
Examine the log output.

^ permalink  raw  reply  [nested|flat] 18+ messages in thread

* Re: BUG #19369: Not documented that io_uring on kernel versions between 5.1 and below 5.6 does not work
@ 2026-01-08 06:52  surya poondla <suryapoondla4@gmail.com>
  parent: surya poondla <suryapoondla4@gmail.com>
  0 siblings, 1 reply; 18+ messages in thread

From: surya poondla @ 2026-01-08 06:52 UTC (permalink / raw)
  To: evsi@amazon.com; pgsql-bugs@lists.postgresql.org

Hi Evan,

In my previous email/findings, I didn't compile postgres with the liburing
 option.

I did it this time and see the same symptoms as you saw.

surya@surya:~/pgdata18$ uname -r
5.4.0-216-generic
surya@surya:~/pgdata18$ uname -a
Linux surya 5.4.0-216-generic #236-Ubuntu SMP Fri Apr 11 19:55:34 UTC 2025
aarch64 aarch64 aarch64 GNU/Linux
surya@surya:~/pgdata18$
surya@surya:~/pgdata18$ ~/pg18/bin/pg_ctl -D ~/pgdata18 restart
waiting for server to shut down.... done
server stopped
waiting for server to start....2026-01-08 06:20:36.301 UTC [17042] LOG:
 redirecting log output to logging collector process
2026-01-08 06:20:36.301 UTC [17042] HINT:  Future log output will appear in
directory "log".
 done
server started
surya@surya:~/pgdata18$ ls log/
postgresql-2026-01-08_061910.log  postgresql-2026-01-08_062036.log
postgresql-2026-01-08_061955.log
surya@surya:~/pgdata18$ ~/pg18/bin/psql -d postgres
psql: error: connection to server on socket "/tmp/.s.PGSQL.5432" failed:
FATAL:  could not read blocks 0..0 in file "global/1260": Invalid argument

In the logs, I see
026-01-08 06:24:29.858 UTC [17126] DEBUG:  InitPostgres
2026-01-08 06:24:29.858 UTC [17127] DEBUG:  logical replication launcher
started
2026-01-08 06:24:29.858 UTC [17127] DEBUG:  InitPostgres
2026-01-08 06:24:29.858 UTC [17126] DEBUG:  io 6400      |op invalid|target
invalid|state HANDED_OUT      : adding cb #1, id
2/aio_shared_buffer_readv_cb
2026-01-08 06:24:29.858 UTC [17126] DEBUG:  io 6400      |op invalid|target
smgr|state HANDED_OUT      : adding cb #2, id 1/aio_md_readv_cb
2026-01-08 06:24:29.858 UTC [17126] DEBUG:  io 6400      |op readv|target
smgr|state DEFINED         : calling cb #1
2/aio_shared_buffer_readv_cb->stage(0)
2026-01-08 06:24:29.859 UTC [17126] DEBUG:  io 6400      |op readv|target
smgr|state STAGED          : staged (synchronous: 0, in_batch: 1)
2026-01-08 06:24:29.859 UTC [17126] DEBUG:  io 6400      |op readv|target
smgr|state SUBMITTED       : wait_one io_gen: 1, ref_gen: 1, cycle 0
2026-01-08 06:24:29.859 UTC [17126] LOG:  could not read blocks 0..0 in
file "global/1262": Invalid argument
2026-01-08 06:24:29.859 UTC [17126] DEBUG:  io 6400      |op readv|target
smgr|state COMPLETED_IO    : after shared completion: distilled result:
(status ERROR, id 1, error_data: 22, result 0), raw_result: -22
2026-01-08 06:24:29.859 UTC [17126] DEBUG:  io 6400      |op readv|target
smgr|state COMPLETED_SHARED: after local completion: result: (status ERROR,
id 1, error_data 22, result 0), raw_result: -22
2026-01-08 06:24:29.859 UTC [17126] DEBUG:  drained 1/1, now expecting 0
2026-01-08 06:24:29.859 UTC [17126] DEBUG:  io 6400      |op invalid|target
invalid|state IDLE            : wait_one io_gen: 2, ref_gen: 1, cycle 0
2026-01-08 06:24:29.859 UTC [17126] DEBUG:  wait_one with 0 sleeps
2026-01-08 06:24:29.859 UTC [17126] ERROR:  could not read blocks 0..0 in
file "global/1262": Invalid argument
2026-01-08 06:24:30.859 UTC [17126] DEBUG:  io 6400      |op invalid|target
invalid|state HANDED_OUT      : adding cb #1, id
2/aio_shared_buffer_readv_cbhe logs

I will do some more testing on this and update my findings.

-Surya Poondla

On Wed, Jan 7, 2026 at 8:15 PM surya poondla <suryapoondla4@gmail.com>
wrote:

> Hi Evsi,
>
> I created a new Ubuntu server and am able to reproduce the same behavior
> you reported for Postgres 18.1 on aarch64 architecture.
>
> surya@surya:~/pgdata18/log$ uname -r
> 5.4.0-216-generic
> surya@surya:~/pgdata18/log$ uname -a
> Linux surya 5.4.0-216-generic #236-Ubuntu SMP Fri Apr 11 19:55:34 UTC 2025
> aarch64 aarch64 aarch64 GNU/Linux
>
> I did some testing and see the below
> In the postgresql.conf if I put
> io_method = 'worker' or io_method = 'sync', postgres is able to restart
> with no errors.
> But if io_method = 'io_uring' then I see the below on my console
>
> surya@surya:~/postgresql-18.1$ vim ~/pgdata18/postgresql.conf
> surya@surya:~/postgresql-18.1$ ~/pg18/bin/pg_ctl -D ~/pgdata18 restart
> waiting for server to shut down....2026-01-08 04:06:07.081 UTC [44973]
> DEBUG:  logger shutting down
> 2026-01-08 04:06:07.081 UTC [44973] DEBUG:  shmem_exit(0): 0
> before_shmem_exit callbacks to make
> 2026-01-08 04:06:07.081 UTC [44973] DEBUG:  shmem_exit(0): 0 on_shmem_exit
> callbacks to make
> 2026-01-08 04:06:07.081 UTC [44973] DEBUG:  proc_exit(0): 0 callbacks to
> make
> 2026-01-08 04:06:07.081 UTC [44973] DEBUG:  exit(0)
> 2026-01-08 04:06:07.081 UTC [44973] DEBUG:  shmem_exit(-1): 0
> before_shmem_exit callbacks to make
> 2026-01-08 04:06:07.081 UTC [44973] DEBUG:  shmem_exit(-1): 0
> on_shmem_exit callbacks to make
> 2026-01-08 04:06:07.081 UTC [44973] DEBUG:  proc_exit(-1): 0 callbacks to
> make
>  done
> server stopped
> waiting for server to start....2026-01-08 04:06:07.172 GMT [44988] LOG:
>  invalid value for parameter "io_method": "io_uring"
> 2026-01-08 04:06:07.172 GMT [44988] HINT:  Available values: sync, worker.
> 2026-01-08 04:06:07.172 UTC [44988] FATAL:  configuration file
> "/home/surya/pgdata18/postgresql.conf" contains errors
> 2026-01-08 04:06:07.172 UTC [44988] DEBUG:  shmem_exit(1): 0
> before_shmem_exit callbacks to make
> 2026-01-08 04:06:07.172 UTC [44988] DEBUG:  shmem_exit(1): 0 on_shmem_exit
> callbacks to make
> 2026-01-08 04:06:07.172 UTC [44988] DEBUG:  proc_exit(1): 0 callbacks to
> make
> 2026-01-08 04:06:07.172 UTC [44988] DEBUG:  exit(1)
>  stopped waiting
> pg_ctl: could not start server
> Examine the log output.
>
>
> From the above we can see that the stderr says that "*invalid value for
> parameter "io_method": "io_uring"*"
>
> And in the logs I see similar thing like you reported
> 2026-01-08 04:05:31.438 UTC [44972] DEBUG:  starting background worker
> process "logical replication launcher"
> 2026-01-08 04:05:31.438 UTC [44981] DEBUG:  autovacuum launcher started
> 2026-01-08 04:05:31.438 UTC [44981] DEBUG:  InitPostgres
> 2026-01-08 04:05:31.438 UTC [44982] DEBUG:  logical replication launcher
> started
> 2026-01-08 04:05:31.438 UTC [44982] DEBUG:  InitPostgres
> 2026-01-08 04:05:31.438 UTC [44981] DEBUG:  io 6400      |op
> invalid|target invalid|state HANDED_OUT      : adding cb #1, id
> 2/aio_shared_buffer_readv_cb
> 2026-01-08 04:05:31.438 UTC [44981] DEBUG:  io 6400      |op
> invalid|target smgr|state HANDED_OUT      : adding cb #2, id
> 1/aio_md_readv_cb
> 2026-01-08 04:05:31.438 UTC [44981] DEBUG:  io 6400      |op readv|target
> smgr|state DEFINED         : calling cb #1
> 2/aio_shared_buffer_readv_cb->stage(0)
> 2026-01-08 04:05:31.438 UTC [44981] DEBUG:  io 6400      |op readv|target
> smgr|state STAGED          : staged (synchronous: 0, in_batch: 1)
> 2026-01-08 04:05:31.439 UTC [44974] DEBUG:  io 6400      |op readv|target
> smgr|state COMPLETED_IO    : after shared completion: distilled result:
> (status OK, id 0, error_data: 0, result 1), raw_result: 8192
> 2026-01-08 04:05:31.439 UTC [44981] DEBUG:  io 6400      |op readv|target
> smgr|state COMPLETED_SHARED: after local completion: result: (status OK, id
> 0, error_data 0, result 1), raw_result: 8192
>
> I am working on a patch and will fix the inconsistencies in documentation
> about io_uring.
>
> Best,
> Surya Poondla
>
> On Wed, Jan 7, 2026 at 7:54 PM PG Bug reporting form <
> noreply@postgresql.org> wrote:
>
>> The following bug has been logged on the website:
>>
>> Bug reference:      19369
>> Logged by:          Evan Si
>> Email address:      evsi@amazon.com
>> PostgreSQL version: 18.1
>> Operating system:   Amazon Linux 2
>> Description:
>>
>> Hello,
>>
>> The documentation doesn't explicitly state a minimum kernel version for
>> io_uring, but in src/backend/storage/aio/README.md, it claims that:
>>
>> > io_method=io_uring is available on Linux 5.1+.
>>
>> Attempting to set io_method to io_uring on versions without io_uring at
>> all
>> (below 5.1) causes the server to graciously report that "[the k]ernel does
>> not support io_uring".
>> But setting io_uring on kernel versions between 5.1 and 5.6 sees the
>> server
>> start but connections failing with EINVAL.
>>
>> ```
>> [ec2-user@ip-172-31-56-49 postgres]$ psql postgres
>> psql: error: connection to server on socket "/tmp/.s.PGSQL.5432" failed:
>> FATAL:  could not read blocks 0..0 in file "global/1260": Invalid argument
>> ```
>>
>> It seems like the implementation in postgres leverages non-vectored I/O
>> (i.e. io_uring_prep_read and io_uring_prep_write) in
>> src/backend/storage/aio/method_io_uring.c.
>>
>> But, these opcodes aren't actually available until kernel 5.6
>> (https://github.com/axboe/liburing/issues/44),
>> (https://man7.org/linux/man-pages/man2/io_uring_enter.2.html - under
>> IORING_OP_READ, IORING_OP_WRITE).
>>
>> It seems kernel 5.4 LTS ended last month, but this seems worth
>> clarifying, I
>> think.
>>
>> --
>>
>> Precise reproduction example:
>>
>> OS details
>> ```
>> [ec2-user@ip-172-31-56-49 postgres]$ uname -a
>> Linux ip-172-31-56-49.us-west-2.compute.internal
>> 5.4.301-221.450.amzn2.x86_64 #1 SMP Tue Nov 18 16:40:04 UTC 2025 x86_64
>> x86_64 x86_64 GNU/Linux
>> ```
>>
>> Build postgres with liburing 2.8, set postgresql.conf with
>> io_method=io_uring, log_min_messages = debug3.
>>
>> Postgres starts without complaint, but trying to connect will fail:
>>
>> ```
>> [ec2-user@ip-172-31-56-49 postgres]$ psql postgres
>> psql: error: connection to server on socket "/tmp/.s.PGSQL.5432" failed:
>> FATAL:  could not read blocks 0..0 in file "global/1260": Invalid argument
>> ```
>> Inside logfile:
>> ```
>> 2026-01-02 22:35:43.862 UTC [8517] DEBUG:  io 6400      |op invalid|target
>> invalid|state HANDED_OUT      : adding cb #1, id
>> 2/aio_shared_buffer_readv_cb
>> 2026-01-02 22:35:43.862 UTC [8517] DEBUG:  io 6400      |op invalid|target
>> smgr|state HANDED_OUT      : adding cb #2, id 1/aio_md_readv_cb
>> 2026-01-02 22:35:43.863 UTC [8517] DEBUG:  io 6400      |op readv|target
>> smgr|state DEFINED         : calling cb #1
>> 2/aio_shared_buffer_readv_cb->stage(0)
>> 2026-01-02 22:35:43.863 UTC [8517] DEBUG:  io 6400      |op readv|target
>> smgr|state STAGED          : staged (synchronous: 0, in_batch: 1)
>> 2026-01-02 22:35:43.863 UTC [8517] DEBUG:  io 6400      |op readv|target
>> smgr|state SUBMITTED       : wait_one io_gen: 3, ref_gen: 3, cycle 0
>> 2026-01-02 22:35:43.863 UTC [8517] LOG:  could not read blocks 0..0 in
>> file
>> "global/1262": Invalid argument
>> 2026-01-02 22:35:43.863 UTC [8517] DEBUG:  io 6400      |op readv|target
>> smgr|state COMPLETED_IO    : after shared completion: distilled result:
>> (status ERROR, id 1, error_data: 22, result 0), raw_result: -22
>> 2026-01-02 22:35:43.863 UTC [8517] DEBUG:  io 6400      |op readv|target
>> smgr|state COMPLETED_SHARED: after local completion: result: (status
>> ERROR,
>> id 1, error_data 22, result 0), raw_result: -22
>> 2026-01-02 22:35:43.863 UTC [8517] DEBUG:  drained 1/1, now expecting 0
>> 2026-01-02 22:35:43.863 UTC [8517] DEBUG:  io 6400      |op invalid|target
>> invalid|state IDLE            : wait_one io_gen: 4, ref_gen: 3, cycle 0
>> 2026-01-02 22:35:43.863 UTC [8517] DEBUG:  wait_one with 0 sleeps
>> 2026-01-02 22:35:43.863 UTC [8517] ERROR:  could not read blocks 0..0 in
>> file "global/1262": Invalid argument
>> 2026-01-02 22:35:44.057 UTC [8512] DEBUG:  assigned pm child slot 1 for
>> backend
>> 2026-01-02 22:35:44.058 UTC [8512] DEBUG:  forked new client backend,
>> pid=8521 socket=151
>> 2026-01-02 22:35:44.058 UTC [8521] DEBUG:  InitPostgres
>> 2026-01-02 22:35:44.059 UTC [8521] DEBUG:  io 0         |op invalid|target
>> invalid|state HANDED_OUT      : adding cb #1, id
>> 2/aio_shared_buffer_readv_cb
>> 2026-01-02 22:35:44.059 UTC [8521] DEBUG:  io 0         |op invalid|target
>> smgr|state HANDED_OUT      : adding cb #2, id 1/aio_md_readv_cb
>> 2026-01-02 22:35:44.059 UTC [8521] DEBUG:  io 0         |op readv|target
>> smgr|state DEFINED         : calling cb #1
>> 2/aio_shared_buffer_readv_cb->stage(0)
>> 2026-01-02 22:35:44.059 UTC [8521] DEBUG:  io 0         |op readv|target
>> smgr|state STAGED          : staged (synchronous: 0, in_batch: 1)
>> 2026-01-02 22:35:44.059 UTC [8521] DEBUG:  io 0         |op readv|target
>> smgr|state SUBMITTED       : wait_one io_gen: 1, ref_gen: 1, cycle 0
>> 2026-01-02 22:35:44.059 UTC [8521] LOG:  could not read blocks 0..0 in
>> file
>> "global/1260": Invalid argument
>> 2026-01-02 22:35:44.059 UTC [8521] DEBUG:  io 0         |op readv|target
>> smgr|state COMPLETED_IO    : after shared completion: distilled result:
>> (status ERROR, id 1, error_data: 22, result 0), raw_result: -22
>> 2026-01-02 22:35:44.059 UTC [8521] DEBUG:  io 0         |op readv|target
>> smgr|state COMPLETED_SHARED: after local completion: result: (status
>> ERROR,
>> id 1, error_data 22, result 0), raw_result: -22
>> 2026-01-02 22:35:44.059 UTC [8521] DEBUG:  drained 1/1, now expecting 0
>> 2026-01-02 22:35:44.059 UTC [8521] DEBUG:  io 0         |op invalid|target
>> invalid|state IDLE            : wait_one io_gen: 2, ref_gen: 1, cycle 0
>> 2026-01-02 22:35:44.059 UTC [8521] DEBUG:  wait_one with 0 sleeps
>> 2026-01-02 22:35:44.059 UTC [8521] FATAL:  could not read blocks 0..0 in
>> file "global/1260": Invalid argument
>> 2026-01-02 22:35:44.059 UTC [8521] DEBUG:  shmem_exit(1): 5
>> before_shmem_exit callbacks to make
>> 2026-01-02 22:35:44.059 UTC [8521] DEBUG:  shmem_exit(1): 7 on_shmem_exit
>> callbacks to make
>> 2026-01-02 22:35:44.059 UTC [8521] DEBUG:  proc_exit(1): 2 callbacks to
>> make
>> 2026-01-02 22:35:44.059 UTC [8521] DEBUG:  exit(1)
>> 2026-01-02 22:35:44.059 UTC [8521] DEBUG:  shmem_exit(-1): 0
>> before_shmem_exit callbacks to make
>> 2026-01-02 22:35:44.059 UTC [8521] DEBUG:  shmem_exit(-1): 0 on_shmem_exit
>> callbacks to make
>> 2026-01-02 22:35:44.059 UTC [8521] DEBUG:  proc_exit(-1): 0 callbacks to
>> make
>> 2026-01-02 22:35:44.060 UTC [8512] DEBUG:  releasing pm child slot 1
>> 2026-01-02 22:35:44.060 UTC [8512] DEBUG:  client backend (PID 8521)
>> exited
>> with exit code 1
>> 2026-01-02 22:35:44.863 UTC [8517] DEBUG:  io 6400      |op invalid|target
>> invalid|state HANDED_OUT      : adding cb #1, id
>> 2/aio_shared_buffer_readv_cb
>> 2026-01-02 22:35:44.863 UTC [8517] DEBUG:  io 6400      |op invalid|target
>> smgr|state HANDED_OUT      : adding cb #2, id 1/aio_md_readv_cb
>> 2026-01-02 22:35:44.863 UTC [8517] DEBUG:  io 6400      |op readv|target
>> smgr|state DEFINED         : calling cb #1
>> 2/aio_shared_buffer_readv_cb->stage(0)
>> 2026-01-02 22:35:44.863 UTC [8517] DEBUG:  io 6400      |op readv|target
>> smgr|state STAGED          : staged (synchronous: 0, in_batch: 1)
>> 2026-01-02 22:35:44.863 UTC [8517] DEBUG:  io 6400      |op readv|target
>> smgr|state SUBMITTED       : wait_one io_gen: 4, ref_gen: 4, cycle 0
>> 2026-01-02 22:35:44.863 UTC [8517] LOG:  could not read blocks 0..0 in
>> file
>> "global/1262": Invalid argument
>> 2026-01-02 22:35:44.863 UTC [8517] DEBUG:  io 6400      |op readv|target
>> smgr|state COMPLETED_IO    : after shared completion: distilled result:
>> (status ERROR, id 1, error_data: 22, result 0), raw_result: -22
>> 2026-01-02 22:35:44.863 UTC [8517] DEBUG:  io 6400      |op readv|target
>> smgr|state COMPLETED_SHARED: after local completion: result: (status
>> ERROR,
>> id 1, error_data 22, result 0), raw_result: -22
>> 2026-01-02 22:35:44.863 UTC [8517] DEBUG:  drained 1/1, now expecting 0
>> 2026-01-02 22:35:44.863 UTC [8517] DEBUG:  io 6400      |op invalid|target
>> invalid|state IDLE            : wait_one io_gen: 5, ref_gen: 4, cycle 0
>> 2026-01-02 22:35:44.863 UTC [8517] DEBUG:  wait_one with 0 sleeps
>> 2026-01-02 22:35:44.863 UTC [8517] ERROR:  could not read blocks 0..0 in
>> file "global/1262": Invalid argument
>> ```
>>
>>

^ permalink  raw  reply  [nested|flat] 18+ messages in thread

* Re: BUG #19369: Not documented that io_uring on kernel versions between 5.1 and below 5.6 does not work
@ 2026-01-12 21:16  Si, Evan <evsi@amazon.com>
  parent: surya poondla <suryapoondla4@gmail.com>
  0 siblings, 1 reply; 18+ messages in thread

From: Si, Evan @ 2026-01-12 21:16 UTC (permalink / raw)
  To: surya poondla <suryapoondla4@gmail.com>; pgsql-bugs@lists.postgresql.org <pgsql-bugs@lists.postgresql.org>

Hi Surya,

Sure, thanks for the interest. Mainly I think it’d be nice to for the engine to behave similarly as it does pre-5.1 and point out that the kernel version is too old. Or at least for the README to reflect the minimum kernel version (5.6) accurately.

Evan

From: surya poondla <suryapoondla4@gmail.com>
Date: Wednesday, January 7, 2026 at 10:53 PM
To: "Si, Evan" <evsi@amazon.com>, "pgsql-bugs@lists.postgresql.org" <pgsql-bugs@lists.postgresql.org>
Subject: RE: [EXTERNAL] BUG #19369: Not documented that io_uring on kernel versions between 5.1 and below 5.6 does not work


CAUTION: This email originated from outside of the organization. Do not click links or open attachments unless you can confirm the sender and know the content is safe.

Hi Evan,

In my previous email/findings, I didn't compile postgres with the liburing option.

I did it this time and see the same symptoms as you saw.

surya@surya:~/pgdata18$ uname -r
5.4.0-216-generic
surya@surya:~/pgdata18$ uname -a
Linux surya 5.4.0-216-generic #236-Ubuntu SMP Fri Apr 11 19:55:34 UTC 2025 aarch64 aarch64 aarch64 GNU/Linux
surya@surya:~/pgdata18$
surya@surya:~/pgdata18$ ~/pg18/bin/pg_ctl -D ~/pgdata18 restart
waiting for server to shut down.... done
server stopped
waiting for server to start....2026-01-08 06:20:36.301 UTC [17042] LOG:  redirecting log output to logging collector process
2026-01-08 06:20:36.301 UTC [17042] HINT:  Future log output will appear in directory "log".
 done
server started
surya@surya:~/pgdata18$ ls log/
postgresql-2026-01-08_061910.log  postgresql-2026-01-08_062036.log
postgresql-2026-01-08_061955.log
surya@surya:~/pgdata18$ ~/pg18/bin/psql -d postgres
psql: error: connection to server on socket "/tmp/.s.PGSQL.5432" failed: FATAL:  could not read blocks 0..0 in file "global/1260": Invalid argument

In the logs, I see
026-01-08 06:24:29.858 UTC [17126] DEBUG:  InitPostgres
2026-01-08 06:24:29.858 UTC [17127] DEBUG:  logical replication launcher started
2026-01-08 06:24:29.858 UTC [17127] DEBUG:  InitPostgres
2026-01-08 06:24:29.858 UTC [17126] DEBUG:  io 6400      |op invalid|target invalid|state HANDED_OUT      : adding cb #1, id 2/aio_shared_buffer_readv_cb
2026-01-08 06:24:29.858 UTC [17126] DEBUG:  io 6400      |op invalid|target smgr|state HANDED_OUT      : adding cb #2, id 1/aio_md_readv_cb
2026-01-08 06:24:29.858 UTC [17126] DEBUG:  io 6400      |op readv|target smgr|state DEFINED         : calling cb #1 2/aio_shared_buffer_readv_cb->stage(0)
2026-01-08 06:24:29.859 UTC [17126] DEBUG:  io 6400      |op readv|target smgr|state STAGED          : staged (synchronous: 0, in_batch: 1)
2026-01-08 06:24:29.859 UTC [17126] DEBUG:  io 6400      |op readv|target smgr|state SUBMITTED       : wait_one io_gen: 1, ref_gen: 1, cycle 0
2026-01-08 06:24:29.859 UTC [17126] LOG:  could not read blocks 0..0 in file "global/1262": Invalid argument
2026-01-08 06:24:29.859 UTC [17126] DEBUG:  io 6400      |op readv|target smgr|state COMPLETED_IO    : after shared completion: distilled result: (status ERROR, id 1, error_data: 22, result 0), raw_result: -22
2026-01-08 06:24:29.859 UTC [17126] DEBUG:  io 6400      |op readv|target smgr|state COMPLETED_SHARED: after local completion: result: (status ERROR, id 1, error_data 22, result 0), raw_result: -22
2026-01-08 06:24:29.859 UTC [17126] DEBUG:  drained 1/1, now expecting 0
2026-01-08 06:24:29.859 UTC [17126] DEBUG:  io 6400      |op invalid|target invalid|state IDLE            : wait_one io_gen: 2, ref_gen: 1, cycle 0
2026-01-08 06:24:29.859 UTC [17126] DEBUG:  wait_one with 0 sleeps
2026-01-08 06:24:29.859 UTC [17126] ERROR:  could not read blocks 0..0 in file "global/1262": Invalid argument
2026-01-08 06:24:30.859 UTC [17126] DEBUG:  io 6400      |op invalid|target invalid|state HANDED_OUT      : adding cb #1, id 2/aio_shared_buffer_readv_cbhe logs

I will do some more testing on this and update my findings.

-Surya Poondla

On Wed, Jan 7, 2026 at 8:15 PM surya poondla <suryapoondla4@gmail.com<mailto:suryapoondla4@gmail.com>> wrote:
Hi Evsi,

I created a new Ubuntu server and am able to reproduce the same behavior you reported for Postgres 18.1 on aarch64 architecture.

surya@surya:~/pgdata18/log$ uname -r
5.4.0-216-generic
surya@surya:~/pgdata18/log$ uname -a
Linux surya 5.4.0-216-generic #236-Ubuntu SMP Fri Apr 11 19:55:34 UTC 2025 aarch64 aarch64 aarch64 GNU/Linux

I did some testing and see the below
In the postgresql.conf if I put
io_method = 'worker' or io_method = 'sync', postgres is able to restart with no errors.
But if io_method = 'io_uring' then I see the below on my console
surya@surya:~/postgresql-18.1$ vim ~/pgdata18/postgresql.conf
surya@surya:~/postgresql-18.1$ ~/pg18/bin/pg_ctl -D ~/pgdata18 restart
waiting for server to shut down....2026-01-08 04:06:07.081 UTC [44973] DEBUG:  logger shutting down
2026-01-08 04:06:07.081 UTC [44973] DEBUG:  shmem_exit(0): 0 before_shmem_exit callbacks to make
2026-01-08 04:06:07.081 UTC [44973] DEBUG:  shmem_exit(0): 0 on_shmem_exit callbacks to make
2026-01-08 04:06:07.081 UTC [44973] DEBUG:  proc_exit(0): 0 callbacks to make
2026-01-08 04:06:07.081 UTC [44973] DEBUG:  exit(0)
2026-01-08 04:06:07.081 UTC [44973] DEBUG:  shmem_exit(-1): 0 before_shmem_exit callbacks to make
2026-01-08 04:06:07.081 UTC [44973] DEBUG:  shmem_exit(-1): 0 on_shmem_exit callbacks to make
2026-01-08 04:06:07.081 UTC [44973] DEBUG:  proc_exit(-1): 0 callbacks to make
 done
server stopped
waiting for server to start....2026-01-08 04:06:07.172 GMT [44988] LOG:  invalid value for parameter "io_method": "io_uring"
2026-01-08 04:06:07.172 GMT [44988] HINT:  Available values: sync, worker.
2026-01-08 04:06:07.172 UTC [44988] FATAL:  configuration file "/home/surya/pgdata18/postgresql.conf" contains errors
2026-01-08 04:06:07.172 UTC [44988] DEBUG:  shmem_exit(1): 0 before_shmem_exit callbacks to make
2026-01-08 04:06:07.172 UTC [44988] DEBUG:  shmem_exit(1): 0 on_shmem_exit callbacks to make
2026-01-08 04:06:07.172 UTC [44988] DEBUG:  proc_exit(1): 0 callbacks to make
2026-01-08 04:06:07.172 UTC [44988] DEBUG:  exit(1)
 stopped waiting
pg_ctl: could not start server
Examine the log output.


From the above we can see that the stderr says that "invalid value for parameter "io_method": "io_uring""

And in the logs I see similar thing like you reported
2026-01-08 04:05:31.438 UTC [44972] DEBUG:  starting background worker process "logical replication launcher"
2026-01-08 04:05:31.438 UTC [44981] DEBUG:  autovacuum launcher started
2026-01-08 04:05:31.438 UTC [44981] DEBUG:  InitPostgres
2026-01-08 04:05:31.438 UTC [44982] DEBUG:  logical replication launcher started
2026-01-08 04:05:31.438 UTC [44982] DEBUG:  InitPostgres
2026-01-08 04:05:31.438 UTC [44981] DEBUG:  io 6400      |op invalid|target invalid|state HANDED_OUT      : adding cb #1, id 2/aio_shared_buffer_readv_cb
2026-01-08 04:05:31.438 UTC [44981] DEBUG:  io 6400      |op invalid|target smgr|state HANDED_OUT      : adding cb #2, id 1/aio_md_readv_cb
2026-01-08 04:05:31.438 UTC [44981] DEBUG:  io 6400      |op readv|target smgr|state DEFINED         : calling cb #1 2/aio_shared_buffer_readv_cb->stage(0)
2026-01-08 04:05:31.438 UTC [44981] DEBUG:  io 6400      |op readv|target smgr|state STAGED          : staged (synchronous: 0, in_batch: 1)
2026-01-08 04:05:31.439 UTC [44974] DEBUG:  io 6400      |op readv|target smgr|state COMPLETED_IO    : after shared completion: distilled result: (status OK, id 0, error_data: 0, result 1), raw_result: 8192
2026-01-08 04:05:31.439 UTC [44981] DEBUG:  io 6400      |op readv|target smgr|state COMPLETED_SHARED: after local completion: result: (status OK, id 0, error_data 0, result 1), raw_result: 8192

I am working on a patch and will fix the inconsistencies in documentation about io_uring.

Best,
Surya Poondla

On Wed, Jan 7, 2026 at 7:54 PM PG Bug reporting form <noreply@postgresql.org<mailto:noreply@postgresql.org>> wrote:
The following bug has been logged on the website:

Bug reference:      19369
Logged by:          Evan Si
Email address:      evsi@amazon.com<mailto:evsi@amazon.com>
PostgreSQL version: 18.1
Operating system:   Amazon Linux 2
Description:

Hello,

The documentation doesn't explicitly state a minimum kernel version for
io_uring, but in src/backend/storage/aio/README.md, it claims that:

> io_method=io_uring is available on Linux 5.1+.

Attempting to set io_method to io_uring on versions without io_uring at all
(below 5.1) causes the server to graciously report that "[the k]ernel does
not support io_uring".
But setting io_uring on kernel versions between 5.1 and 5.6 sees the server
start but connections failing with EINVAL.

```
[ec2-user@ip-172-31-56-49 postgres]$ psql postgres
psql: error: connection to server on socket "/tmp/.s.PGSQL.5432" failed:
FATAL:  could not read blocks 0..0 in file "global/1260": Invalid argument
```

It seems like the implementation in postgres leverages non-vectored I/O
(i.e. io_uring_prep_read and io_uring_prep_write) in
src/backend/storage/aio/method_io_uring.c.

But, these opcodes aren't actually available until kernel 5.6
(https://github.com/axboe/liburing/issues/44),
(https://man7.org/linux/man-pages/man2/io_uring_enter.2.html - under
IORING_OP_READ, IORING_OP_WRITE).

It seems kernel 5.4 LTS ended last month, but this seems worth clarifying, I
think.

--

Precise reproduction example:

OS details
```
[ec2-user@ip-172-31-56-49 postgres]$ uname -a
Linux ip-172-31-56-49.us-west-2.compute.internal
5.4.301-221.450.amzn2.x86_64 #1 SMP Tue Nov 18 16:40:04 UTC 2025 x86_64
x86_64 x86_64 GNU/Linux
```

Build postgres with liburing 2.8, set postgresql.conf with
io_method=io_uring, log_min_messages = debug3.

Postgres starts without complaint, but trying to connect will fail:

```
[ec2-user@ip-172-31-56-49 postgres]$ psql postgres
psql: error: connection to server on socket "/tmp/.s.PGSQL.5432" failed:
FATAL:  could not read blocks 0..0 in file "global/1260": Invalid argument
```
Inside logfile:
```
2026-01-02 22:35:43.862 UTC [8517] DEBUG:  io 6400      |op invalid|target
invalid|state HANDED_OUT      : adding cb #1, id
2/aio_shared_buffer_readv_cb
2026-01-02 22:35:43.862 UTC [8517] DEBUG:  io 6400      |op invalid|target
smgr|state HANDED_OUT      : adding cb #2, id 1/aio_md_readv_cb
2026-01-02 22:35:43.863 UTC [8517] DEBUG:  io 6400      |op readv|target
smgr|state DEFINED         : calling cb #1
2/aio_shared_buffer_readv_cb->stage(0)
2026-01-02 22:35:43.863 UTC [8517] DEBUG:  io 6400      |op readv|target
smgr|state STAGED          : staged (synchronous: 0, in_batch: 1)
2026-01-02 22:35:43.863 UTC [8517] DEBUG:  io 6400      |op readv|target
smgr|state SUBMITTED       : wait_one io_gen: 3, ref_gen: 3, cycle 0
2026-01-02 22:35:43.863 UTC [8517] LOG:  could not read blocks 0..0 in file
"global/1262": Invalid argument
2026-01-02 22:35:43.863 UTC [8517] DEBUG:  io 6400      |op readv|target
smgr|state COMPLETED_IO    : after shared completion: distilled result:
(status ERROR, id 1, error_data: 22, result 0), raw_result: -22
2026-01-02 22:35:43.863 UTC [8517] DEBUG:  io 6400      |op readv|target
smgr|state COMPLETED_SHARED: after local completion: result: (status ERROR,
id 1, error_data 22, result 0), raw_result: -22
2026-01-02 22:35:43.863 UTC [8517] DEBUG:  drained 1/1, now expecting 0
2026-01-02 22:35:43.863 UTC [8517] DEBUG:  io 6400      |op invalid|target
invalid|state IDLE            : wait_one io_gen: 4, ref_gen: 3, cycle 0
2026-01-02 22:35:43.863 UTC [8517] DEBUG:  wait_one with 0 sleeps
2026-01-02 22:35:43.863 UTC [8517] ERROR:  could not read blocks 0..0 in
file "global/1262": Invalid argument
2026-01-02 22:35:44.057 UTC [8512] DEBUG:  assigned pm child slot 1 for
backend
2026-01-02 22:35:44.058 UTC [8512] DEBUG:  forked new client backend,
pid=8521 socket=151
2026-01-02 22:35:44.058 UTC [8521] DEBUG:  InitPostgres
2026-01-02 22:35:44.059 UTC [8521] DEBUG:  io 0         |op invalid|target
invalid|state HANDED_OUT      : adding cb #1, id
2/aio_shared_buffer_readv_cb
2026-01-02 22:35:44.059 UTC [8521] DEBUG:  io 0         |op invalid|target
smgr|state HANDED_OUT      : adding cb #2, id 1/aio_md_readv_cb
2026-01-02 22:35:44.059 UTC [8521] DEBUG:  io 0         |op readv|target
smgr|state DEFINED         : calling cb #1
2/aio_shared_buffer_readv_cb->stage(0)
2026-01-02 22:35:44.059 UTC [8521] DEBUG:  io 0         |op readv|target
smgr|state STAGED          : staged (synchronous: 0, in_batch: 1)
2026-01-02 22:35:44.059 UTC [8521] DEBUG:  io 0         |op readv|target
smgr|state SUBMITTED       : wait_one io_gen: 1, ref_gen: 1, cycle 0
2026-01-02 22:35:44.059 UTC [8521] LOG:  could not read blocks 0..0 in file
"global/1260": Invalid argument
2026-01-02 22:35:44.059 UTC [8521] DEBUG:  io 0         |op readv|target
smgr|state COMPLETED_IO    : after shared completion: distilled result:
(status ERROR, id 1, error_data: 22, result 0), raw_result: -22
2026-01-02 22:35:44.059 UTC [8521] DEBUG:  io 0         |op readv|target
smgr|state COMPLETED_SHARED: after local completion: result: (status ERROR,
id 1, error_data 22, result 0), raw_result: -22
2026-01-02 22:35:44.059 UTC [8521] DEBUG:  drained 1/1, now expecting 0
2026-01-02 22:35:44.059 UTC [8521] DEBUG:  io 0         |op invalid|target
invalid|state IDLE            : wait_one io_gen: 2, ref_gen: 1, cycle 0
2026-01-02 22:35:44.059 UTC [8521] DEBUG:  wait_one with 0 sleeps
2026-01-02 22:35:44.059 UTC [8521] FATAL:  could not read blocks 0..0 in
file "global/1260": Invalid argument
2026-01-02 22:35:44.059 UTC [8521] DEBUG:  shmem_exit(1): 5
before_shmem_exit callbacks to make
2026-01-02 22:35:44.059 UTC [8521] DEBUG:  shmem_exit(1): 7 on_shmem_exit
callbacks to make
2026-01-02 22:35:44.059 UTC [8521] DEBUG:  proc_exit(1): 2 callbacks to make
2026-01-02 22:35:44.059 UTC [8521] DEBUG:  exit(1)
2026-01-02 22:35:44.059 UTC [8521] DEBUG:  shmem_exit(-1): 0
before_shmem_exit callbacks to make
2026-01-02 22:35:44.059 UTC [8521] DEBUG:  shmem_exit(-1): 0 on_shmem_exit
callbacks to make
2026-01-02 22:35:44.059 UTC [8521] DEBUG:  proc_exit(-1): 0 callbacks to
make
2026-01-02 22:35:44.060 UTC [8512] DEBUG:  releasing pm child slot 1
2026-01-02 22:35:44.060 UTC [8512] DEBUG:  client backend (PID 8521) exited
with exit code 1
2026-01-02 22:35:44.863 UTC [8517] DEBUG:  io 6400      |op invalid|target
invalid|state HANDED_OUT      : adding cb #1, id
2/aio_shared_buffer_readv_cb
2026-01-02 22:35:44.863 UTC [8517] DEBUG:  io 6400      |op invalid|target
smgr|state HANDED_OUT      : adding cb #2, id 1/aio_md_readv_cb
2026-01-02 22:35:44.863 UTC [8517] DEBUG:  io 6400      |op readv|target
smgr|state DEFINED         : calling cb #1
2/aio_shared_buffer_readv_cb->stage(0)
2026-01-02 22:35:44.863 UTC [8517] DEBUG:  io 6400      |op readv|target
smgr|state STAGED          : staged (synchronous: 0, in_batch: 1)
2026-01-02 22:35:44.863 UTC [8517] DEBUG:  io 6400      |op readv|target
smgr|state SUBMITTED       : wait_one io_gen: 4, ref_gen: 4, cycle 0
2026-01-02 22:35:44.863 UTC [8517] LOG:  could not read blocks 0..0 in file
"global/1262": Invalid argument
2026-01-02 22:35:44.863 UTC [8517] DEBUG:  io 6400      |op readv|target
smgr|state COMPLETED_IO    : after shared completion: distilled result:
(status ERROR, id 1, error_data: 22, result 0), raw_result: -22
2026-01-02 22:35:44.863 UTC [8517] DEBUG:  io 6400      |op readv|target
smgr|state COMPLETED_SHARED: after local completion: result: (status ERROR,
id 1, error_data 22, result 0), raw_result: -22
2026-01-02 22:35:44.863 UTC [8517] DEBUG:  drained 1/1, now expecting 0
2026-01-02 22:35:44.863 UTC [8517] DEBUG:  io 6400      |op invalid|target
invalid|state IDLE            : wait_one io_gen: 5, ref_gen: 4, cycle 0
2026-01-02 22:35:44.863 UTC [8517] DEBUG:  wait_one with 0 sleeps
2026-01-02 22:35:44.863 UTC [8517] ERROR:  could not read blocks 0..0 in
file "global/1262": Invalid argument
```


^ permalink  raw  reply  [nested|flat] 18+ messages in thread

* Re: BUG #19369: Not documented that io_uring on kernel versions between 5.1 and below 5.6 does not work
@ 2026-01-13 16:59  Andres Freund <andres@anarazel.de>
  parent: Si, Evan <evsi@amazon.com>
  0 siblings, 1 reply; 18+ messages in thread

From: Andres Freund @ 2026-01-13 16:59 UTC (permalink / raw)
  To: Si, Evan <evsi@amazon.com>; +Cc: surya poondla <suryapoondla4@gmail.com>; pgsql-bugs@lists.postgresql.org <pgsql-bugs@lists.postgresql.org>

Hi,

On 2026-01-12 21:16:48 +0000, Si, Evan wrote:
> Hi Surya,
> 
> Sure, thanks for the interest. Mainly I think it’d be nice to for the engine
> to behave similarly as it does pre-5.1 and point out that the kernel version
> is too old. Or at least for the README to reflect the minimum kernel version
> (5.6) accurately.

Yea, this clearly is just an oversight. I had forgotten that those operations
weren't available in earlier kernel versions.

While it would be possible to make things work on the older kernel, by
always using the vectorized op on old kernels, I'm doubtful it's worth the
increase in test matrix.

Any chance you want to provide a patch?


Greetings,

Andres Freund





^ permalink  raw  reply  [nested|flat] 18+ messages in thread

* Re: BUG #19369: Not documented that io_uring on kernel versions between 5.1 and below 5.6 does not work
@ 2026-01-13 19:06  surya poondla <suryapoondla4@gmail.com>
  parent: Andres Freund <andres@anarazel.de>
  0 siblings, 2 replies; 18+ messages in thread

From: surya poondla @ 2026-01-13 19:06 UTC (permalink / raw)
  To: Andres Freund <andres@anarazel.de>; +Cc: Si, Evan <evsi@amazon.com>; pgsql-bugs@lists.postgresql.org <pgsql-bugs@lists.postgresql.org>

Hi Evan, Andres,

Here is the patch (attached).

I believe this change would also be a good candidate for backpatching to
previous supported versions.


Regards, Surya Poondla

Attachments:

  [application/octet-stream] 0001-Document-correct-kernel-requirements-for-io_uring.patch (2.3K, ../../CAOVWO5p5z10mbsjyzWfv0m4gdGcAjtnat991qLWKYRJEc5sAew@mail.gmail.com/3-0001-Document-correct-kernel-requirements-for-io_uring.patch)
  download | inline diff:
From 497eb813c0c41d870e3659c29876d42e750f666c Mon Sep 17 00:00:00 2001
From: spoondla <s_poondla@apple.com>
Date: Mon, 12 Jan 2026 15:29:48 -0800
Subject: [PATCH] Document correct kernel requirements for io_uring

While io_uring was introduced in Linux 5.1, PostgreSQL requires kernel
version 5.6 or newer due to the io_uring operations it relies on.
Earlier kernels may appear to support io_uring but can fail at runtime.

Updated the internal AIO documentation and the sample configuration file
to state the correct minimum kernel requirement.
---
 src/backend/storage/aio/README.md             | 8 +++++++-
 src/backend/utils/misc/postgresql.conf.sample | 2 +-
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/src/backend/storage/aio/README.md b/src/backend/storage/aio/README.md
index 72ae3b3737d..c40a6ce16cf 100644
--- a/src/backend/storage/aio/README.md
+++ b/src/backend/storage/aio/README.md
@@ -256,10 +256,16 @@ synchronous manner.
 
 #### io_uring
 
-`io_method=io_uring` is available on Linux 5.1+. In contrast to worker mode it
+`io_method=io_uring` is available on Linux 5.6+. In contrast to worker mode it
 dispatches all IO from within the process, lowering context switch rate /
 latency.
 
+While io_uring was introduced in Linux kernel 5.1, the operations required by
+PostgreSQL (IORING_OP_READ and IORING_OP_WRITE opcodes for non-vectored I/O)
+are only available starting with Linux kernel 5.6. Attempting to use io_uring
+on kernels between 5.1 and 5.5 will result in runtime errors (EINVAL) when
+connections are established.
+
 
 ### AIO Handles
 
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index dc9e2255f8a..1648f4be207 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -204,7 +204,7 @@
                                         # (change requires restart)
 #io_combine_limit = 128kB               # usually 1-128 blocks (depends on OS)
 
-#io_method = worker                     # worker, io_uring, sync
+#io_method = worker                     # worker, io_uring (Linux 5.6+), sync
                                         # (change requires restart)
 #io_max_concurrency = -1                # Max number of IOs that one process
                                         # can execute simultaneously
-- 
2.39.5 (Apple Git-154)



^ permalink  raw  reply  [nested|flat] 18+ messages in thread

* Re: BUG #19369: Not documented that io_uring on kernel versions between 5.1 and below 5.6 does not work
@ 2026-01-13 19:11  Andres Freund <andres@anarazel.de>
  parent: surya poondla <suryapoondla4@gmail.com>
  1 sibling, 0 replies; 18+ messages in thread

From: Andres Freund @ 2026-01-13 19:11 UTC (permalink / raw)
  To: surya poondla <suryapoondla4@gmail.com>; +Cc: Si, Evan <evsi@amazon.com>; pgsql-bugs@lists.postgresql.org <pgsql-bugs@lists.postgresql.org>

Hi,

On 2026-01-13 11:06:20 -0800, surya poondla wrote:
> Hi Evan, Andres,
> 
> Here is the patch (attached).

I think we ought to not just document the difference, but also emit a useful
error message at startup...

> I believe this change would also be a good candidate for backpatching to
> previous supported versions.

Yes, once we have something mergeable, it should definitely be added to 18
too.

Greetings,

Andres Freund





^ permalink  raw  reply  [nested|flat] 18+ messages in thread

* Re: BUG #19369: Not documented that io_uring on kernel versions between 5.1 and below 5.6 does not work
@ 2026-01-14 18:15  Pierre Forstmann <pierre.forstmann@gmail.com>
  parent: surya poondla <suryapoondla4@gmail.com>
  1 sibling, 1 reply; 18+ messages in thread

From: Pierre Forstmann @ 2026-01-14 18:15 UTC (permalink / raw)
  To: surya poondla <suryapoondla4@gmail.com>; Andres Freund <andres@anarazel.de>; +Cc: Si, Evan <evsi@amazon.com>; pgsql-bugs@lists.postgresql.org <pgsql-bugs@lists.postgresql.org>

Hello,

Is asynchronous I/O as introduced in PG 18 also available for Windows 
platform and possibly for Solaris, AIX, FreeBSD platforms ?

If not maybe we should also mention in Server Configuration section that 
asynchronous I/O configuration is only available on Linux platforms.

Is there any other feature only available for specific platforms ? I 
have not found a documentation section mentioning such cases (except for 
installations 
https://www.postgresql.org/docs/18/installation-platform-notes.html).

PF

Le 13/01/2026 à 20:06, surya poondla a écrit :
>
> Hi Evan, Andres,
>
> Here is the patch (attached).
>
> I believe this change would also be a good candidate for backpatching 
> to previous supported versions.
>
> Regards, Surya Poondla
>

^ permalink  raw  reply  [nested|flat] 18+ messages in thread

* Re: BUG #19369: Not documented that io_uring on kernel versions between 5.1 and below 5.6 does not work
@ 2026-01-14 18:18  Andres Freund <andres@anarazel.de>
  parent: Pierre Forstmann <pierre.forstmann@gmail.com>
  0 siblings, 1 reply; 18+ messages in thread

From: Andres Freund @ 2026-01-14 18:18 UTC (permalink / raw)
  To: Pierre Forstmann <pierre.forstmann@gmail.com>; +Cc: surya poondla <suryapoondla4@gmail.com>; Si, Evan <evsi@amazon.com>; pgsql-bugs@lists.postgresql.org <pgsql-bugs@lists.postgresql.org>

Hi,

On 2026-01-14 19:15:17 +0100, Pierre Forstmann wrote:
> Is asynchronous I/O as introduced in PG 18 also available for Windows
> platform and possibly for Solaris, AIX, FreeBSD platforms ?

Yes, but only using io_method=worker.

Greetings,

Andres Freund





^ permalink  raw  reply  [nested|flat] 18+ messages in thread

* Re: BUG #19369: Not documented that io_uring on kernel versions between 5.1 and below 5.6 does not work
@ 2026-01-14 20:26  Laurenz Albe <laurenz.albe@cybertec.at>
  parent: Andres Freund <andres@anarazel.de>
  0 siblings, 1 reply; 18+ messages in thread

From: Laurenz Albe @ 2026-01-14 20:26 UTC (permalink / raw)
  To: Andres Freund <andres@anarazel.de>; Pierre Forstmann <pierre.forstmann@gmail.com>; +Cc: surya poondla <suryapoondla4@gmail.com>; Si, Evan <evsi@amazon.com>; pgsql-bugs@lists.postgresql.org <pgsql-bugs@lists.postgresql.org>

On Wed, 2026-01-14 at 13:18 -0500, Andres Freund wrote:
> On 2026-01-14 19:15:17 +0100, Pierre Forstmann wrote:
> > Is asynchronous I/O as introduced in PG 18 also available for Windows
> > platform and possibly for Solaris, AIX, FreeBSD platforms ?
> 
> Yes, but only using io_method=worker.

Well, AIX is currently unsupported...

Yours,
Laurenz Albe





^ permalink  raw  reply  [nested|flat] 18+ messages in thread

* Re: BUG #19369: Not documented that io_uring on kernel versions between 5.1 and below 5.6 does not work
@ 2026-01-14 21:07  surya poondla <suryapoondla4@gmail.com>
  parent: Laurenz Albe <laurenz.albe@cybertec.at>
  0 siblings, 2 replies; 18+ messages in thread

From: surya poondla @ 2026-01-14 21:07 UTC (permalink / raw)
  To: Laurenz Albe <laurenz.albe@cybertec.at>; +Cc: Andres Freund <andres@anarazel.de>; Pierre Forstmann <pierre.forstmann@gmail.com>; Si, Evan <evsi@amazon.com>; pgsql-bugs@lists.postgresql.org <pgsql-bugs@lists.postgresql.org>

"I think we ought to not just document the difference, but also emit a
useful
error message at startup..."
Sure Andres, I am working on a patch which emits a useful error message too.

^ permalink  raw  reply  [nested|flat] 18+ messages in thread

* Re: BUG #19369: Not documented that io_uring on kernel versions between 5.1 and below 5.6 does not work
@ 2026-01-15 07:32  Pierre Forstmann <pierre.forstmann@gmail.com>
  parent: surya poondla <suryapoondla4@gmail.com>
  1 sibling, 0 replies; 18+ messages in thread

From: Pierre Forstmann @ 2026-01-15 07:32 UTC (permalink / raw)
  To: surya poondla <suryapoondla4@gmail.com>; +Cc: Andres Freund <andres@anarazel.de>; Si, Evan <evsi@amazon.com>; pgsql-bugs@lists.postgresql.org <pgsql-bugs@lists.postgresql.org>; Laurenz Albe <laurenz.albe@cybertec.at>

I have already proposed a patch in pgsql-hackers mailing lists:

see 
https://www.postgresql.org/message-id/5c251f33-8463-4736-aef7-6873b37e48a5%40gmail.com

Le 14/01/2026 à 22:07, surya poondla a écrit :
> "I think we ought to not just document the difference, but also emit a 
> useful
> error message at startup..."
> Sure Andres, I am working on a patch which emits a useful error 
> message too.





^ permalink  raw  reply  [nested|flat] 18+ messages in thread

* Re: BUG #19369: Not documented that io_uring on kernel versions between 5.1 and below 5.6 does not work
@ 2026-01-15 20:27  surya poondla <suryapoondla4@gmail.com>
  parent: surya poondla <suryapoondla4@gmail.com>
  1 sibling, 1 reply; 18+ messages in thread

From: surya poondla @ 2026-01-15 20:27 UTC (permalink / raw)
  To: Laurenz Albe <laurenz.albe@cybertec.at>; +Cc: Andres Freund <andres@anarazel.de>; Pierre Forstmann <pierre.forstmann@gmail.com>; Si, Evan <evsi@amazon.com>; pgsql-bugs@lists.postgresql.org <pgsql-bugs@lists.postgresql.org>

>
> Sure Andres, I am working on a patch which emits a useful error message
> too.
>


Hi All,


I prepared a patch that implements an early detection of unsupported
io_uring operations during PostgreSQL startup, before any I/O is attempted.
The patch focuses on

  1. Clear error message at startup instead of cryptic EINVAL during
queries.

  2. Immediate failure with actionable hints (upgrade kernel or use
io_method=worker)

  3. Prevents PostgreSQL from starting in a broken state


Before the patch:

  1. PostgreSQL started successfully

  2. Connection attempts failed with EINVAL errors


After patch:

  1. PostgreSQL refuses to start

  2. Clear error message that looks like:

    "FATAL: kernel does not support required io_uring operations"
    "DETAIL:  The kernel supports io_uring but lacks one or more of the
required opcodes (IORING_OP_READ, IORING_OP_WRITE, IORING_OP_READV,
IORING_OP_WRITEV). This typically occurs on Linux kernels older than 5.6."

    "HINT: Either upgrade your kernel to version 5.6 or newer, or

     use io_method=worker"


Modified files in the Patch:

  1. configure.ac: Added io_uring_opcode_supported to AC_CHECK_FUNCS

  2. meson.build: Added corresponding function check for Meson build

  3. src/backend/storage/aio/method_io_uring.c: Added
is_uring_read_write_unsupported() function, that is integrated into
pgaio_uring_init() and reports clear error with details and hints.


I tested the patch on Ubuntu server with Linux kernel 5.4.0-216-generic,
and when io_uring is enabled I see that postgres doesn’t start (expected
behavior).


The existing error handling for kernels < 5.1 (ENOSYS) is preserved.


Regards,
Surya Poondla

Attachments:

  [application/octet-stream] v2-0001-Document-correct-kernel-requirements-for-io_uring.patch (7.6K, ../../CAOVWO5q5hoQvLM_xY-yGDyn7kv-s8Dg7uTcTfqqqPHVjFYKJ1Q@mail.gmail.com/3-v2-0001-Document-correct-kernel-requirements-for-io_uring.patch)
  download | inline diff:
From c4342f7117df0c7ab420155d8e2726a5f0a8dd6e Mon Sep 17 00:00:00 2001
From: spoondla <s_poondla@apple.com>
Date: Mon, 12 Jan 2026 15:29:48 -0800
Subject: [PATCH v2] Document correct kernel requirements for io_uring Add
 startup-time kernel version check for io_uring

While io_uring was introduced in Linux 5.1, PostgreSQL requires kernel
version 5.6 or newer due to the io_uring operations it relies on.
Earlier kernels may appear to support io_uring but can fail at runtime.

Updated the internal AIO documentation and the sample configuration file
to state the correct minimum kernel requirement.
---
 configure.ac                                  |   2 +-
 meson.build                                   |   5 +
 src/backend/storage/aio/README.md             |   8 +-
 src/backend/storage/aio/method_io_uring.c     | 108 ++++++++++++++++++
 src/backend/utils/misc/postgresql.conf.sample |   2 +-
 5 files changed, 122 insertions(+), 3 deletions(-)

diff --git a/configure.ac b/configure.ac
index 145197e6bd6..f056966c25b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1417,7 +1417,7 @@ fi
 if test "$with_liburing" = yes; then
   _LIBS="$LIBS"
   LIBS="$LIBURING_LIBS $LIBS"
-  AC_CHECK_FUNCS([io_uring_queue_init_mem])
+  AC_CHECK_FUNCS([io_uring_queue_init_mem io_uring_opcode_supported])
   LIBS="$_LIBS"
 fi
 
diff --git a/meson.build b/meson.build
index 555c94796c6..c4a5271a18b 100644
--- a/meson.build
+++ b/meson.build
@@ -1040,6 +1040,11 @@ if liburing.found()
     cdata.set('HAVE_IO_URING_QUEUE_INIT_MEM', 1)
   endif
 
+  if cc.has_function('io_uring_opcode_supported',
+      dependencies: liburing, args: test_c_args)
+    cdata.set('HAVE_IO_URING_OPCODE_SUPPORTED', 1)
+  endif
+
 endif
 
 
diff --git a/src/backend/storage/aio/README.md b/src/backend/storage/aio/README.md
index 72ae3b3737d..c40a6ce16cf 100644
--- a/src/backend/storage/aio/README.md
+++ b/src/backend/storage/aio/README.md
@@ -256,10 +256,16 @@ synchronous manner.
 
 #### io_uring
 
-`io_method=io_uring` is available on Linux 5.1+. In contrast to worker mode it
+`io_method=io_uring` is available on Linux 5.6+. In contrast to worker mode it
 dispatches all IO from within the process, lowering context switch rate /
 latency.
 
+While io_uring was introduced in Linux kernel 5.1, the operations required by
+PostgreSQL (IORING_OP_READ and IORING_OP_WRITE opcodes for non-vectored I/O)
+are only available starting with Linux kernel 5.6. Attempting to use io_uring
+on kernels between 5.1 and 5.5 will result in runtime errors (EINVAL) when
+connections are established.
+
 
 ### AIO Handles
 
diff --git a/src/backend/storage/aio/method_io_uring.c b/src/backend/storage/aio/method_io_uring.c
index af58c6118ac..2853c92eb15 100644
--- a/src/backend/storage/aio/method_io_uring.c
+++ b/src/backend/storage/aio/method_io_uring.c
@@ -30,6 +30,7 @@
 #ifdef IOMETHOD_IO_URING_ENABLED
 
 #include <sys/mman.h>
+#include <sys/utsname.h>
 #include <unistd.h>
 
 #include <liburing.h>
@@ -225,6 +226,96 @@ pgaio_uring_check_capabilities(void)
 	pgaio_uring_caps.checked = true;
 }
 
+/*
+ * Check if the kernel supports the required io_uring operations.
+ *
+ * PostgreSQL requires four io_uring opcodes:
+ *   - IORING_OP_READ and IORING_OP_WRITE (added in kernel 5.6)
+ *   - IORING_OP_READV and IORING_OP_WRITEV (added in kernel 5.1)
+ *
+ * While io_uring was introduced in Linux 5.1 with vectored operations,
+ * the non-vectored READ/WRITE opcodes weren't added until 5.6. Since
+ * PostgreSQL uses all four, we need kernel 5.6+.
+ *
+ * Rather than checking kernel version (which is unreliable due to vendor
+ * backports), we probe for actual opcode support when possible.
+ *
+ * Returns true if any required opcode is NOT supported.
+ */
+static bool
+is_uring_read_write_unsupported(void)
+{
+	struct io_uring test_ring;
+	struct io_uring_params p = {0};
+	int			ret;
+	bool		unsupported = false;
+
+	/* Create a temporary ring to probe capabilities */
+	ret = io_uring_queue_init(2, &test_ring, 0);
+	if (ret < 0)
+	{
+		/*
+		 * If we can't even create a ring, let the normal initialization path
+		 * handle the error with appropriate messages.
+		 */
+		return false;
+	}
+
+#ifdef HAVE_IO_URING_OPCODE_SUPPORTED
+	/*
+	 * Use io_uring_opcode_supported() if available (liburing 2.1+).
+	 * This directly queries the kernel for opcode support.
+	 *
+	 * PostgreSQL uses both single-buffer (READ/WRITE) and vectored
+	 * (READV/WRITEV) operations. READV/WRITEV were added in kernel 5.1,
+	 * but READ/WRITE were added in kernel 5.6. Check for all four to
+	 * ensure complete support.
+	 */
+	if (!io_uring_opcode_supported(&test_ring, IORING_OP_READ) ||
+		!io_uring_opcode_supported(&test_ring, IORING_OP_WRITE) ||
+		!io_uring_opcode_supported(&test_ring, IORING_OP_READV) ||
+		!io_uring_opcode_supported(&test_ring, IORING_OP_WRITEV))
+	{
+		unsupported = true;
+	}
+#else
+	/*
+	 * Fallback: Try to probe by checking if we can prepare read operations.
+	 * Kernels without IORING_OP_READ support will fail later, but at least
+	 * we tried. This is less reliable but works with older liburing.
+	 */
+	{
+		struct io_uring_sqe *sqe;
+
+		sqe = io_uring_get_sqe(&test_ring);
+		if (sqe)
+		{
+			/*
+			 * Prepare a dummy read operation. On kernels without
+			 * IORING_OP_READ support, this will be accepted here but fail
+			 * with EINVAL when submitted. We'd need to actually submit to
+			 * detect, but that requires a valid fd. The version check is a
+			 * reasonable fallback.
+			 */
+			struct utsname uts;
+			int			major,
+						minor;
+
+			if (uname(&uts) == 0 &&
+				sscanf(uts.release, "%d.%d", &major, &minor) == 2)
+			{
+				/* Known problematic kernel range */
+				if (major == 5 && minor >= 1 && minor <= 5)
+					unsupported = true;
+			}
+		}
+	}
+#endif
+
+	io_uring_queue_exit(&test_ring);
+	return unsupported;
+}
+
 /*
  * Memory for all PgAioUringContext instances
  */
@@ -284,6 +375,23 @@ pgaio_uring_shmem_init(bool first_time)
 	size_t		ring_mem_remain = 0;
 	char	   *ring_mem_next = 0;
 
+	/*
+	 * Check if the kernel supports the required io_uring operations before
+	 * attempting full initialization. Kernels without all required opcodes
+	 * (IORING_OP_READ, WRITE, READV, WRITEV) will cause runtime EINVAL errors.
+	 */
+	if (is_uring_read_write_unsupported())
+	{
+		ereport(ERROR,
+				errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				errmsg("kernel does not support required io_uring operations"),
+				errdetail("The kernel supports io_uring but lacks one or more of the "
+						  "required opcodes (IORING_OP_READ, IORING_OP_WRITE, "
+						  "IORING_OP_READV, IORING_OP_WRITEV). "
+						  "This typically occurs on Linux kernels older than 5.6."),
+				errhint("Either upgrade your kernel to version 5.6 or newer, or use io_method=worker."));
+	}
+
 	/*
 	 * We allocate memory for all PgAioUringContext instances and, if
 	 * supported, the memory required for each of the io_uring instances, in
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index dc9e2255f8a..1648f4be207 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -204,7 +204,7 @@
                                         # (change requires restart)
 #io_combine_limit = 128kB               # usually 1-128 blocks (depends on OS)
 
-#io_method = worker                     # worker, io_uring, sync
+#io_method = worker                     # worker, io_uring (Linux 5.6+), sync
                                         # (change requires restart)
 #io_max_concurrency = -1                # Max number of IOs that one process
                                         # can execute simultaneously
-- 
2.39.5 (Apple Git-154)



^ permalink  raw  reply  [nested|flat] 18+ messages in thread

* Re: BUG #19369: Not documented that io_uring on kernel versions between 5.1 and below 5.6 does not work
@ 2026-01-23 18:22  surya poondla <suryapoondla4@gmail.com>
  parent: surya poondla <suryapoondla4@gmail.com>
  0 siblings, 2 replies; 18+ messages in thread

From: surya poondla @ 2026-01-23 18:22 UTC (permalink / raw)
  To: Laurenz Albe <laurenz.albe@cybertec.at>; +Cc: Andres Freund <andres@anarazel.de>; Pierre Forstmann <pierre.forstmann@gmail.com>; Si, Evan <evsi@amazon.com>; pgsql-bugs@lists.postgresql.org <pgsql-bugs@lists.postgresql.org>

Hi All,

I created a commitfest entry for this patch (
https://commitfest.postgresql.org/patch/6428/)

Kindly review it and let me know of any changes.

Regards,
Surya Poondla

>

^ permalink  raw  reply  [nested|flat] 18+ messages in thread

* Re: BUG #19369: Not documented that io_uring on kernel versions between 5.1 and below 5.6 does not work
@ 2026-08-26 14:38  Pierre Forstmann <pierre.forstmann@gmail.com>
  parent: surya poondla <suryapoondla4@gmail.com>
  1 sibling, 0 replies; 18+ messages in thread

From: Pierre Forstmann @ 2026-08-26 14:38 UTC (permalink / raw)
  To: pgsql-hackers@lists.postgresql.org; +Cc: Surya Poondla <suryapoondla4@gmail.com>

Hello,

When compiling I get following warning:

[932/1889] Compiling C object src/backend/postgres_lib.a.p/storage_aio_method_io_uring.c.o
../src/backend/storage/aio/method_io_uring.c: In function ‘is_uring_read_write_unsupported’:
../src/backend/storage/aio/method_io_uring.c:253:32: warning: unused variable ‘p’ [-Wunused-variable]
  253 |         struct io_uring_params p = {0};

Could you please fix this ?

I also would like to know if you manage to run the equivalent of 'make installcheck-world" with meson ?
I cannot: see my message of 16:33 CET.

Regards
PF

The new status of this patch is: Waiting on Author


^ permalink  raw  reply  [nested|flat] 18+ messages in thread

* Re: BUG #19369: Not documented that io_uring on kernel versions between 5.1 and below 5.6 does not work
@ 2026-08-26 22:02  surya poondla <suryapoondla4@gmail.com>
  parent: surya poondla <suryapoondla4@gmail.com>
  1 sibling, 1 reply; 18+ messages in thread

From: surya poondla @ 2026-08-26 22:02 UTC (permalink / raw)
  To: Laurenz Albe <laurenz.albe@cybertec.at>; +Cc: Andres Freund <andres@anarazel.de>; Pierre Forstmann <pierre.forstmann@gmail.com>; Si, Evan <evsi@amazon.com>; pgsql-bugs@lists.postgresql.org <pgsql-bugs@lists.postgresql.org>

Hi All,

I rebased the patch. Please find the latest patch.

Regards,
Surya Poondla

Attachments:

  [application/octet-stream] v3-0001-Document-correct-kernel-requirements-for-io_uring.patch (7.6K, ../../CAOVWO5pfR0-183qw0GXJ6hTqWGEUVOgp3DX-aU=bhMRbRr9f+g@mail.gmail.com/3-v3-0001-Document-correct-kernel-requirements-for-io_uring.patch)
  download | inline diff:
From 39207823341f07aa4f82e60385fef4f5b0ae4dd1 Mon Sep 17 00:00:00 2001
From: spoondla <s_poondla@apple.com>
Date: Mon, 12 Jan 2026 15:29:48 -0800
Subject: [PATCH v2] Document correct kernel requirements for io_uring Add
 startup-time kernel version check for io_uring

While io_uring was introduced in Linux 5.1, PostgreSQL requires kernel
version 5.6 or newer due to the io_uring operations it relies on.
Earlier kernels may appear to support io_uring but can fail at runtime.

Updated the internal AIO documentation and the sample configuration file
to state the correct minimum kernel requirement.
---
 configure.ac                                  |   2 +-
 meson.build                                   |   5 +
 src/backend/storage/aio/README.md             |   8 +-
 src/backend/storage/aio/method_io_uring.c     | 108 ++++++++++++++++++
 src/backend/utils/misc/postgresql.conf.sample |   2 +-
 5 files changed, 122 insertions(+), 3 deletions(-)

diff --git a/configure.ac b/configure.ac
index a331749fcb5..2085a297230 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1465,7 +1465,7 @@ fi
 if test "$with_liburing" = yes; then
   _LIBS="$LIBS"
   LIBS="$LIBURING_LIBS $LIBS"
-  AC_CHECK_FUNCS([io_uring_queue_init_mem])
+  AC_CHECK_FUNCS([io_uring_queue_init_mem io_uring_opcode_supported])
   LIBS="$_LIBS"
 fi
 
diff --git a/meson.build b/meson.build
index f4cde249242..bbedd25a496 100644
--- a/meson.build
+++ b/meson.build
@@ -1123,6 +1123,11 @@ if liburing.found()
     cdata.set('HAVE_IO_URING_QUEUE_INIT_MEM', 1)
   endif
 
+  if cc.has_function('io_uring_opcode_supported',
+      dependencies: liburing, args: test_c_args)
+    cdata.set('HAVE_IO_URING_OPCODE_SUPPORTED', 1)
+  endif
+
 endif
 
 
diff --git a/src/backend/storage/aio/README.md b/src/backend/storage/aio/README.md
index 72ae3b3737d..c40a6ce16cf 100644
--- a/src/backend/storage/aio/README.md
+++ b/src/backend/storage/aio/README.md
@@ -256,10 +256,16 @@ synchronous manner.
 
 #### io_uring
 
-`io_method=io_uring` is available on Linux 5.1+. In contrast to worker mode it
+`io_method=io_uring` is available on Linux 5.6+. In contrast to worker mode it
 dispatches all IO from within the process, lowering context switch rate /
 latency.
 
+While io_uring was introduced in Linux kernel 5.1, the operations required by
+PostgreSQL (IORING_OP_READ and IORING_OP_WRITE opcodes for non-vectored I/O)
+are only available starting with Linux kernel 5.6. Attempting to use io_uring
+on kernels between 5.1 and 5.5 will result in runtime errors (EINVAL) when
+connections are established.
+
 
 ### AIO Handles
 
diff --git a/src/backend/storage/aio/method_io_uring.c b/src/backend/storage/aio/method_io_uring.c
index 3ffe5061a20..3f56bbf9c29 100644
--- a/src/backend/storage/aio/method_io_uring.c
+++ b/src/backend/storage/aio/method_io_uring.c
@@ -30,6 +30,7 @@
 #ifdef IOMETHOD_IO_URING_ENABLED
 
 #include <sys/mman.h>
+#include <sys/utsname.h>
 #include <unistd.h>
 
 #include <liburing.h>
@@ -229,6 +230,96 @@ pgaio_uring_check_capabilities(void)
 	pgaio_uring_caps.checked = true;
 }
 
+/*
+ * Check if the kernel supports the required io_uring operations.
+ *
+ * PostgreSQL requires four io_uring opcodes:
+ *   - IORING_OP_READ and IORING_OP_WRITE (added in kernel 5.6)
+ *   - IORING_OP_READV and IORING_OP_WRITEV (added in kernel 5.1)
+ *
+ * While io_uring was introduced in Linux 5.1 with vectored operations,
+ * the non-vectored READ/WRITE opcodes weren't added until 5.6. Since
+ * PostgreSQL uses all four, we need kernel 5.6+.
+ *
+ * Rather than checking kernel version (which is unreliable due to vendor
+ * backports), we probe for actual opcode support when possible.
+ *
+ * Returns true if any required opcode is NOT supported.
+ */
+static bool
+is_uring_read_write_unsupported(void)
+{
+	struct io_uring test_ring;
+	struct io_uring_params p = {0};
+	int			ret;
+	bool		unsupported = false;
+
+	/* Create a temporary ring to probe capabilities */
+	ret = io_uring_queue_init(2, &test_ring, 0);
+	if (ret < 0)
+	{
+		/*
+		 * If we can't even create a ring, let the normal initialization path
+		 * handle the error with appropriate messages.
+		 */
+		return false;
+	}
+
+#ifdef HAVE_IO_URING_OPCODE_SUPPORTED
+	/*
+	 * Use io_uring_opcode_supported() if available (liburing 2.1+).
+	 * This directly queries the kernel for opcode support.
+	 *
+	 * PostgreSQL uses both single-buffer (READ/WRITE) and vectored
+	 * (READV/WRITEV) operations. READV/WRITEV were added in kernel 5.1,
+	 * but READ/WRITE were added in kernel 5.6. Check for all four to
+	 * ensure complete support.
+	 */
+	if (!io_uring_opcode_supported(&test_ring, IORING_OP_READ) ||
+		!io_uring_opcode_supported(&test_ring, IORING_OP_WRITE) ||
+		!io_uring_opcode_supported(&test_ring, IORING_OP_READV) ||
+		!io_uring_opcode_supported(&test_ring, IORING_OP_WRITEV))
+	{
+		unsupported = true;
+	}
+#else
+	/*
+	 * Fallback: Try to probe by checking if we can prepare read operations.
+	 * Kernels without IORING_OP_READ support will fail later, but at least
+	 * we tried. This is less reliable but works with older liburing.
+	 */
+	{
+		struct io_uring_sqe *sqe;
+
+		sqe = io_uring_get_sqe(&test_ring);
+		if (sqe)
+		{
+			/*
+			 * Prepare a dummy read operation. On kernels without
+			 * IORING_OP_READ support, this will be accepted here but fail
+			 * with EINVAL when submitted. We'd need to actually submit to
+			 * detect, but that requires a valid fd. The version check is a
+			 * reasonable fallback.
+			 */
+			struct utsname uts;
+			int			major,
+						minor;
+
+			if (uname(&uts) == 0 &&
+				sscanf(uts.release, "%d.%d", &major, &minor) == 2)
+			{
+				/* Known problematic kernel range */
+				if (major == 5 && minor >= 1 && minor <= 5)
+					unsupported = true;
+			}
+		}
+	}
+#endif
+
+	io_uring_queue_exit(&test_ring);
+	return unsupported;
+}
+
 /*
  * Memory for all PgAioUringContext instances
  */
@@ -296,6 +387,23 @@ pgaio_uring_shmem_init(void *arg)
 	size_t		ring_mem_remain = 0;
 	char	   *ring_mem_next = 0;
 
+	/*
+	 * Check if the kernel supports the required io_uring operations before
+	 * attempting full initialization. Kernels without all required opcodes
+	 * (IORING_OP_READ, WRITE, READV, WRITEV) will cause runtime EINVAL errors.
+	 */
+	if (is_uring_read_write_unsupported())
+	{
+		ereport(ERROR,
+				errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				errmsg("kernel does not support required io_uring operations"),
+				errdetail("The kernel supports io_uring but lacks one or more of the "
+						  "required opcodes (IORING_OP_READ, IORING_OP_WRITE, "
+						  "IORING_OP_READV, IORING_OP_WRITEV). "
+						  "This typically occurs on Linux kernels older than 5.6."),
+				errhint("Either upgrade your kernel to version 5.6 or newer, or use io_method=worker."));
+	}
+
 	/*
 	 * We allocate memory for all PgAioUringContext instances and, if
 	 * supported, the memory required for each of the io_uring instances, in
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index e759f06b50f..51e22055622 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -216,7 +216,7 @@
                                         # (change requires restart)
 #io_combine_limit = 128kB               # usually 1-128 blocks (depends on OS)
 
-#io_method = worker                     # worker, io_uring, sync
+#io_method = worker                     # worker, io_uring (Linux 5.6+), sync
                                         # (change requires restart)
 #io_max_concurrency = -1                # Max number of IOs that one process
                                         # can execute simultaneously
-- 
2.39.5 (Apple Git-154)



^ permalink  raw  reply  [nested|flat] 18+ messages in thread

* Re: BUG #19369: Not documented that io_uring on kernel versions between 5.1 and below 5.6 does not work
@ 2026-08-26 23:28  surya poondla <suryapoondla4@gmail.com>
  parent: surya poondla <suryapoondla4@gmail.com>
  0 siblings, 1 reply; 18+ messages in thread

From: surya poondla @ 2026-08-26 23:28 UTC (permalink / raw)
  To: Pierre Forstmann <pierre.forstmann@gmail.com>; +Cc: Andres Freund <andres@anarazel.de>; Si, Evan <evsi@amazon.com>; pgsql-bugs@lists.postgresql.org <pgsql-bugs@lists.postgresql.org>; Laurenz Albe <laurenz.albe@cybertec.at>

Hi Pierre,

Thank you for the review.

I fixed the compiler warning in v4.

I also would like to know if you manage to run the equivalent of 'make
> installcheck-world" with meson ?


I couldn't either. I noticed the "meson test --setup running" was running
SQL suites (regress, isolation) only and  not the TAP suite.
So it does not look equivalent to installcheck-world in any case.

I am doing some additional testing and will update my findings.

Regards,
Surya Poondla

Attachments:

  [application/octet-stream] v4-0001-Document-correct-kernel-requirements-for-io_uring.patch (7.5K, ../../CAOVWO5oVccTRo9RsJvjMCRuBppu_R5Azo+-dq0cQyhds5_4XXw@mail.gmail.com/3-v4-0001-Document-correct-kernel-requirements-for-io_uring.patch)
  download | inline diff:
From 98c966ee7131f2c47bb5fd20d09c99d3b9a52621 Mon Sep 17 00:00:00 2001
From: spoondla <s_poondla@apple.com>
Date: Mon, 12 Jan 2026 15:29:48 -0800
Subject: [PATCH v4] Document correct kernel requirements for io_uring Add
 startup-time kernel version check for io_uring

While io_uring was introduced in Linux 5.1, PostgreSQL requires kernel
version 5.6 or newer due to the io_uring operations it relies on.
Earlier kernels may appear to support io_uring but can fail at runtime.

Updated the internal AIO documentation and the sample configuration file
to state the correct minimum kernel requirement.
---
 configure.ac                                  |   2 +-
 meson.build                                   |   5 +
 src/backend/storage/aio/README.md             |   8 +-
 src/backend/storage/aio/method_io_uring.c     | 107 ++++++++++++++++++
 src/backend/utils/misc/postgresql.conf.sample |   2 +-
 5 files changed, 121 insertions(+), 3 deletions(-)

diff --git a/configure.ac b/configure.ac
index a331749fcb5..2085a297230 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1465,7 +1465,7 @@ fi
 if test "$with_liburing" = yes; then
   _LIBS="$LIBS"
   LIBS="$LIBURING_LIBS $LIBS"
-  AC_CHECK_FUNCS([io_uring_queue_init_mem])
+  AC_CHECK_FUNCS([io_uring_queue_init_mem io_uring_opcode_supported])
   LIBS="$_LIBS"
 fi
 
diff --git a/meson.build b/meson.build
index f4cde249242..bbedd25a496 100644
--- a/meson.build
+++ b/meson.build
@@ -1123,6 +1123,11 @@ if liburing.found()
     cdata.set('HAVE_IO_URING_QUEUE_INIT_MEM', 1)
   endif
 
+  if cc.has_function('io_uring_opcode_supported',
+      dependencies: liburing, args: test_c_args)
+    cdata.set('HAVE_IO_URING_OPCODE_SUPPORTED', 1)
+  endif
+
 endif
 
 
diff --git a/src/backend/storage/aio/README.md b/src/backend/storage/aio/README.md
index 72ae3b3737d..c40a6ce16cf 100644
--- a/src/backend/storage/aio/README.md
+++ b/src/backend/storage/aio/README.md
@@ -256,10 +256,16 @@ synchronous manner.
 
 #### io_uring
 
-`io_method=io_uring` is available on Linux 5.1+. In contrast to worker mode it
+`io_method=io_uring` is available on Linux 5.6+. In contrast to worker mode it
 dispatches all IO from within the process, lowering context switch rate /
 latency.
 
+While io_uring was introduced in Linux kernel 5.1, the operations required by
+PostgreSQL (IORING_OP_READ and IORING_OP_WRITE opcodes for non-vectored I/O)
+are only available starting with Linux kernel 5.6. Attempting to use io_uring
+on kernels between 5.1 and 5.5 will result in runtime errors (EINVAL) when
+connections are established.
+
 
 ### AIO Handles
 
diff --git a/src/backend/storage/aio/method_io_uring.c b/src/backend/storage/aio/method_io_uring.c
index 3ffe5061a20..bc716882fd6 100644
--- a/src/backend/storage/aio/method_io_uring.c
+++ b/src/backend/storage/aio/method_io_uring.c
@@ -30,6 +30,7 @@
 #ifdef IOMETHOD_IO_URING_ENABLED
 
 #include <sys/mman.h>
+#include <sys/utsname.h>
 #include <unistd.h>
 
 #include <liburing.h>
@@ -229,6 +230,95 @@ pgaio_uring_check_capabilities(void)
 	pgaio_uring_caps.checked = true;
 }
 
+/*
+ * Check if the kernel supports the required io_uring operations.
+ *
+ * PostgreSQL requires four io_uring opcodes:
+ *   - IORING_OP_READ and IORING_OP_WRITE (added in kernel 5.6)
+ *   - IORING_OP_READV and IORING_OP_WRITEV (added in kernel 5.1)
+ *
+ * While io_uring was introduced in Linux 5.1 with vectored operations,
+ * the non-vectored READ/WRITE opcodes weren't added until 5.6. Since
+ * PostgreSQL uses all four, we need kernel 5.6+.
+ *
+ * Rather than checking kernel version (which is unreliable due to vendor
+ * backports), we probe for actual opcode support when possible.
+ *
+ * Returns true if any required opcode is NOT supported.
+ */
+static bool
+is_uring_read_write_unsupported(void)
+{
+	struct io_uring test_ring;
+	int			ret;
+	bool		unsupported = false;
+
+	/* Create a temporary ring to probe capabilities */
+	ret = io_uring_queue_init(2, &test_ring, 0);
+	if (ret < 0)
+	{
+		/*
+		 * If we can't even create a ring, let the normal initialization path
+		 * handle the error with appropriate messages.
+		 */
+		return false;
+	}
+
+#ifdef HAVE_IO_URING_OPCODE_SUPPORTED
+	/*
+	 * Use io_uring_opcode_supported() if available (liburing 2.1+).
+	 * This directly queries the kernel for opcode support.
+	 *
+	 * PostgreSQL uses both single-buffer (READ/WRITE) and vectored
+	 * (READV/WRITEV) operations. READV/WRITEV were added in kernel 5.1,
+	 * but READ/WRITE were added in kernel 5.6. Check for all four to
+	 * ensure complete support.
+	 */
+	if (!io_uring_opcode_supported(&test_ring, IORING_OP_READ) ||
+		!io_uring_opcode_supported(&test_ring, IORING_OP_WRITE) ||
+		!io_uring_opcode_supported(&test_ring, IORING_OP_READV) ||
+		!io_uring_opcode_supported(&test_ring, IORING_OP_WRITEV))
+	{
+		unsupported = true;
+	}
+#else
+	/*
+	 * Fallback: Try to probe by checking if we can prepare read operations.
+	 * Kernels without IORING_OP_READ support will fail later, but at least
+	 * we tried. This is less reliable but works with older liburing.
+	 */
+	{
+		struct io_uring_sqe *sqe;
+
+		sqe = io_uring_get_sqe(&test_ring);
+		if (sqe)
+		{
+			/*
+			 * Prepare a dummy read operation. On kernels without
+			 * IORING_OP_READ support, this will be accepted here but fail
+			 * with EINVAL when submitted. We'd need to actually submit to
+			 * detect, but that requires a valid fd. The version check is a
+			 * reasonable fallback.
+			 */
+			struct utsname uts;
+			int			major,
+						minor;
+
+			if (uname(&uts) == 0 &&
+				sscanf(uts.release, "%d.%d", &major, &minor) == 2)
+			{
+				/* Known problematic kernel range */
+				if (major == 5 && minor >= 1 && minor <= 5)
+					unsupported = true;
+			}
+		}
+	}
+#endif
+
+	io_uring_queue_exit(&test_ring);
+	return unsupported;
+}
+
 /*
  * Memory for all PgAioUringContext instances
  */
@@ -296,6 +386,23 @@ pgaio_uring_shmem_init(void *arg)
 	size_t		ring_mem_remain = 0;
 	char	   *ring_mem_next = 0;
 
+	/*
+	 * Check if the kernel supports the required io_uring operations before
+	 * attempting full initialization. Kernels without all required opcodes
+	 * (IORING_OP_READ, WRITE, READV, WRITEV) will cause runtime EINVAL errors.
+	 */
+	if (is_uring_read_write_unsupported())
+	{
+		ereport(ERROR,
+				errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				errmsg("kernel does not support required io_uring operations"),
+				errdetail("The kernel supports io_uring but lacks one or more of the "
+						  "required opcodes (IORING_OP_READ, IORING_OP_WRITE, "
+						  "IORING_OP_READV, IORING_OP_WRITEV). "
+						  "This typically occurs on Linux kernels older than 5.6."),
+				errhint("Either upgrade your kernel to version 5.6 or newer, or use io_method=worker."));
+	}
+
 	/*
 	 * We allocate memory for all PgAioUringContext instances and, if
 	 * supported, the memory required for each of the io_uring instances, in
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index e759f06b50f..51e22055622 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -216,7 +216,7 @@
                                         # (change requires restart)
 #io_combine_limit = 128kB               # usually 1-128 blocks (depends on OS)
 
-#io_method = worker                     # worker, io_uring, sync
+#io_method = worker                     # worker, io_uring (Linux 5.6+), sync
                                         # (change requires restart)
 #io_max_concurrency = -1                # Max number of IOs that one process
                                         # can execute simultaneously
-- 
2.39.5 (Apple Git-154)



^ permalink  raw  reply  [nested|flat] 18+ messages in thread

* Re: BUG #19369: Not documented that io_uring on kernel versions between 5.1 and below 5.6 does not work
@ 2026-08-27 15:49  Pierre Forstmann <pierre.forstmann@gmail.com>
  parent: surya poondla <suryapoondla4@gmail.com>
  0 siblings, 0 replies; 18+ messages in thread

From: Pierre Forstmann @ 2026-08-27 15:49 UTC (permalink / raw)
  To: surya poondla <suryapoondla4@gmail.com>; +Cc: Andres Freund <andres@anarazel.de>; Si, Evan <evsi@amazon.com>; pgsql-bugs@lists.postgresql.org <pgsql-bugs@lists.postgresql.org>; Laurenz Albe <laurenz.albe@cybertec.at>

Hi Surya,

I confirm that the compiler warning is fixed in patch v4.

About testing with meson I use following commands:

# make check
meson test -C build --print-errorlogs --suite setup --suite regress
# make installcheck-world
meson test -C build -q --print-errorlogs --setup running

I have used Ubuntu 2004 to reproduce the issue with Linux kernel 5.4.

After applying the patch and setting io_method=io_uring ,I have checked 
that PG cannot be restarted:

2026-08-27 14:54:13.787 UTC [98714] FATAL:  kernel does not support 
required io_uring operations
2026-08-27 14:54:13.787 UTC [98714] DETAIL:  The kernel supports 
io_uring but lacks one or more of the required opcodes (IORING_OP_READ, 
IORING_OP_WRITE, IORING_OP_READV, IORING_OP_WRITEV). This typically 
occurs on Linux kernels older than 5.6.
2026-08-27 14:54:13.787 UTC [98714] HINT:  Either upgrade your kernel to 
version 5.6 or newer, or use io_method=worker.
2026-08-27 14:54:13.788 UTC [98714] LOG:  database system is shut down

I have checked this with building PG with make and with meson.

I have also reviewed the source code and I have question about following 
code section:

#ifdef HAVE_IO_URING_OPCODE_SUPPORTED
         /*
          * Use io_uring_opcode_supported() if available (liburing 2.1+).
          * This directly queries the kernel for opcode support.
          *
          * PostgreSQL uses both single-buffer (READ/WRITE) and vectored
          * (READV/WRITEV) operations. READV/WRITEV were added in kernel 
5.1,
          * but READ/WRITE were added in kernel 5.6. Check for all four to
          * ensure complete support.
          */
         if (!io_uring_opcode_supported(&test_ring, IORING_OP_READ) ||
                 !io_uring_opcode_supported(&test_ring, IORING_OP_WRITE) ||
                 !io_uring_opcode_supported(&test_ring, IORING_OP_READV) ||
                 !io_uring_opcode_supported(&test_ring, IORING_OP_WRITEV))
         {
                 unsupported = true;
         }
#else


I have tried to compile the routine "is_uring_read_write_unsupported" 
in  a standalone executable and I get following errors:

taio.c: In function ‘is_uring_read_write_unsupported’:
taio.c:63:40: error: passing argument 1 of ‘io_uring_opcode_supported’ 
from incompatible pointer type [-Wincompatible-pointer-types]
    63 |         if (!io_uring_opcode_supported(&test_ring, 
IORING_OP_READ) ||
       |                                        ^~~~~~~~~~
       |                                        |
       |                                        struct io_uring *
In file included from taio.c:16:
/usr/include/liburing.h:153:74: note: expected ‘const struct 
io_uring_probe *’ but argument is of type ‘struct io_uring *’
   153 | IOURINGINLINE int io_uring_opcode_supported(const struct 
io_uring_probe *p,
       |  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
taio.c:64:44: error: passing argument 1 of ‘io_uring_opcode_supported’ 
from incompatible pointer type [-Wincompatible-pointer-types]
    64 |  !io_uring_opcode_supported(&test_ring, IORING_OP_WRITE) ||
       |                                            ^~~~~~~~~~
       |                                            |
       |                                            struct io_uring *
/usr/include/liburing.h:153:74: note: expected ‘const struct 
io_uring_probe *’ but argument is of type ‘struct io_uring *’
   153 | IOURINGINLINE int io_uring_opcode_supported(const struct 
io_uring_probe *p,
       |  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
taio.c:65:44: error: passing argument 1 of ‘io_uring_opcode_supported’ 
from incompatible pointer type [-Wincompatible-pointer-types]
    65 |  !io_uring_opcode_supported(&test_ring, IORING_OP_READV) ||
       |                                            ^~~~~~~~~~
       |                                            |
       |                                            struct io_uring *
/usr/include/liburing.h:153:74: note: expected ‘const struct 
io_uring_probe *’ but argument is of type ‘struct io_uring *’
   153 | IOURINGINLINE int io_uring_opcode_supported(const struct 
io_uring_probe *p,
       |  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
taio.c:66:44: error: passing argument 1 of ‘io_uring_opcode_supported’ 
from incompatible pointer type [-Wincompatible-pointer-types]
    66 |  !io_uring_opcode_supported(&test_ring, IORING_OP_WRITEV))
       |                                            ^~~~~~~~~~
       |                                            |
       |                                            struct io_uring *
/usr/include/liburing.h:153:74: note: expected ‘const struct 
io_uring_probe *’ but argument is of type ‘struct io_uring *’
   153 | IOURINGINLINE int io_uring_opcode_supported(const struct 
io_uring_probe *p,
       |  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^

I get these errors both with Debian 13 and Ubuntu 2004.

Can you double-check if this is the right way to call 
io_uring_opcode_support and/or if there is an issue with make/meson 
configuration ?

Regards,

PF



Le 27/08/2026 à 01:28, surya poondla a écrit :
> Hi Pierre,
>
> Thank you for the review.
>
> I fixed the compiler warning in v4.
>
>     I also would like to know if you manage to run the equivalent of
>     'make installcheck-world" with meson ?
>
>
> I couldn't either. I noticed the "meson test --setup running" was 
> running SQL suites (regress, isolation) only and  not the TAP suite.
> So it does not look equivalent to installcheck-world in any case.
>
> I am doing some additional testing and will update my findings.
>
> Regards,
> Surya Poondla

^ permalink  raw  reply  [nested|flat] 18+ messages in thread


end of thread, other threads:[~2026-08-27 15:49 UTC | newest]

Thread overview: 18+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2026-01-02 22:46 BUG #19369: Not documented that io_uring on kernel versions between 5.1 and below 5.6 does not work PG Bug reporting form <noreply@postgresql.org>
2026-01-08 04:15 ` surya poondla <suryapoondla4@gmail.com>
2026-01-08 06:52   ` surya poondla <suryapoondla4@gmail.com>
2026-01-12 21:16     ` Si, Evan <evsi@amazon.com>
2026-01-13 16:59       ` Andres Freund <andres@anarazel.de>
2026-01-13 19:06         ` surya poondla <suryapoondla4@gmail.com>
2026-01-13 19:11           ` Andres Freund <andres@anarazel.de>
2026-01-14 18:15           ` Pierre Forstmann <pierre.forstmann@gmail.com>
2026-01-14 18:18             ` Andres Freund <andres@anarazel.de>
2026-01-14 20:26               ` Laurenz Albe <laurenz.albe@cybertec.at>
2026-01-14 21:07                 ` surya poondla <suryapoondla4@gmail.com>
2026-01-15 07:32                   ` Pierre Forstmann <pierre.forstmann@gmail.com>
2026-01-15 20:27                   ` surya poondla <suryapoondla4@gmail.com>
2026-01-23 18:22                     ` surya poondla <suryapoondla4@gmail.com>
2026-08-26 14:38                       ` Pierre Forstmann <pierre.forstmann@gmail.com>
2026-08-26 22:02                       ` surya poondla <suryapoondla4@gmail.com>
2026-08-26 23:28                         ` surya poondla <suryapoondla4@gmail.com>
2026-08-27 15:49                           ` Pierre Forstmann <pierre.forstmann@gmail.com>

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox