aboutsummaryrefslogtreecommitdiff
path: root/src/backend/storage/buffer/bufmgr.c
diff options
context:
space:
mode:
authorAndres Freund <andres@anarazel.de>2025-04-07 15:20:30 -0400
committerAndres Freund <andres@anarazel.de>2025-04-07 15:20:30 -0400
commit8e293e689bab0267d26e3705fe1d537cd43e633a (patch)
tree94949fb05110c8f67698f77cc344cd937424b40d /src/backend/storage/buffer/bufmgr.c
parent8ab4241b9f4f73f2168bcaebc990f8b0a6b7bc81 (diff)
downloadpostgresql-8e293e689bab0267d26e3705fe1d537cd43e633a.tar.gz
postgresql-8e293e689bab0267d26e3705fe1d537cd43e633a.zip
aio: Make AIO more compatible with valgrind
In some edge cases valgrind flags issues with the memory referenced by IOs. All of the cases addressed in this change are false positives. Most of the false positives are caused by UnpinBuffer[NoOwner] marking buffer data as inaccessible. This happens even though the AIO subsystem still holds a pin. That's good, there shouldn't be accesses to the buffer outside of AIO related code until it is pinned by "user" code again. But it requires some explicit work - if the buffer is not pinned by the current backend, we need to explicitly mark the buffer data accessible/inaccessible while executing completion callbacks. That however causes a cascading issue in IO workers: After the completion callbacks for a buffer is executed, the page is marked as inaccessible. If subsequently the same worker is executing IO targeting the same buffer, we would get an error, as the memory is still marked inaccessible. To avoid that, we need to explicitly mark the memory as accessible in IO workers. Another issue is that IO executed in workers or via io_uring will not mark memory as DEFINED. In the case of workers that is because valgrind does not track memory definedness across processes. For io_uring that is because valgrind does not understand io_uring, and therefore its IOs never mark memory as defined, whether the completions are processed in the defining process or in another context. It's not entirely clear how to best solve that. The current user of AIO is not affected, as it explicitly marks buffers as DEFINED & NOACCESS anyway. Defer solving this issue until we have a user with different needs. Per buildfarm animal skink. Reviewed-by: Noah Misch <noah@leadboat.com> Co-authored-by: Noah Misch <noah@leadboat.com> Discussion: https://postgr.es/m/3pd4322mogfmdd5nln3zphdwhtmq3rzdldqjwb2sfqzcgs22lf@ok2gletdaoe6
Diffstat (limited to 'src/backend/storage/buffer/bufmgr.c')
-rw-r--r--src/backend/storage/buffer/bufmgr.c19
1 files changed, 19 insertions, 0 deletions
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index 5da121872f4..941d7fa3d94 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -6881,6 +6881,19 @@ buffer_readv_complete_one(PgAioTargetData *td, uint8 buf_off, Buffer buffer,
/* Check for garbage data. */
if (!failed)
{
+ /*
+ * If the buffer is not currently pinned by this backend, e.g. because
+ * we're completing this IO after an error, the buffer data will have
+ * been marked as inaccessible when the buffer was unpinned. The AIO
+ * subsystem holds a pin, but that doesn't prevent the buffer from
+ * having been marked as inaccessible. The completion might also be
+ * executed in a different process.
+ */
+#ifdef USE_VALGRIND
+ if (!BufferIsPinned(buffer))
+ VALGRIND_MAKE_MEM_DEFINED(bufdata, BLCKSZ);
+#endif
+
if (!PageIsVerified((Page) bufdata, tag.blockNum, piv_flags,
failed_checksum))
{
@@ -6899,6 +6912,12 @@ buffer_readv_complete_one(PgAioTargetData *td, uint8 buf_off, Buffer buffer,
else if (*failed_checksum)
*ignored_checksum = true;
+ /* undo what we did above */
+#ifdef USE_VALGRIND
+ if (!BufferIsPinned(buffer))
+ VALGRIND_MAKE_MEM_NOACCESS(bufdata, BLCKSZ);
+#endif
+
/*
* Immediately log a message about the invalid page, but only to the
* server log. The reason to do so immediately is that this may be