summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/storage/aio/aio_io.c23
-rw-r--r--src/backend/storage/aio/method_worker.c19
-rw-r--r--src/backend/storage/buffer/bufmgr.c19
-rw-r--r--src/backend/storage/smgr/smgr.c2
-rw-r--r--src/include/storage/aio_internal.h1
5 files changed, 64 insertions, 0 deletions
diff --git a/src/backend/storage/aio/aio_io.c b/src/backend/storage/aio/aio_io.c
index 4d31392ddc7..00e176135a6 100644
--- a/src/backend/storage/aio/aio_io.c
+++ b/src/backend/storage/aio/aio_io.c
@@ -210,3 +210,26 @@ pgaio_io_uses_fd(PgAioHandle *ioh, int fd)
return false; /* silence compiler */
}
+
+/*
+ * Return the iovec and its length. Currently only expected to be used by
+ * debugging infrastructure
+ */
+int
+pgaio_io_get_iovec_length(PgAioHandle *ioh, struct iovec **iov)
+{
+ Assert(ioh->state >= PGAIO_HS_DEFINED);
+
+ *iov = &pgaio_ctl->iovecs[ioh->iovec_off];
+
+ switch (ioh->op)
+ {
+ case PGAIO_OP_READV:
+ return ioh->op_data.read.iov_length;
+ case PGAIO_OP_WRITEV:
+ return ioh->op_data.write.iov_length;
+ default:
+ pg_unreachable();
+ return 0;
+ }
+}
diff --git a/src/backend/storage/aio/method_worker.c b/src/backend/storage/aio/method_worker.c
index 31d94ac82c5..8ad17ec1ef7 100644
--- a/src/backend/storage/aio/method_worker.c
+++ b/src/backend/storage/aio/method_worker.c
@@ -42,6 +42,7 @@
#include "storage/latch.h"
#include "storage/proc.h"
#include "tcop/tcopprot.h"
+#include "utils/memdebug.h"
#include "utils/ps_status.h"
#include "utils/wait_event.h"
@@ -530,6 +531,24 @@ IoWorkerMain(const void *startup_data, size_t startup_data_len)
error_ioh = NULL;
/*
+ * As part of IO completion the buffer will be marked as NOACCESS,
+ * until the buffer is pinned again - which never happens in io
+ * workers. Therefore the next time there is IO for the same
+ * buffer, the memory will be considered inaccessible. To avoid
+ * that, explicitly allow access to the memory before reading data
+ * into it.
+ */
+#ifdef USE_VALGRIND
+ {
+ struct iovec *iov;
+ uint16 iov_length = pgaio_io_get_iovec_length(ioh, &iov);
+
+ for (int i = 0; i < iov_length; i++)
+ VALGRIND_MAKE_MEM_UNDEFINED(iov[i].iov_base, iov[i].iov_len);
+ }
+#endif
+
+ /*
* We don't expect this to ever fail with ERROR or FATAL, no need
* to keep error_ioh set to the IO.
* pgaio_io_perform_synchronously() contains a critical section to
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
diff --git a/src/backend/storage/smgr/smgr.c b/src/backend/storage/smgr/smgr.c
index 4540284f581..bce37a36d51 100644
--- a/src/backend/storage/smgr/smgr.c
+++ b/src/backend/storage/smgr/smgr.c
@@ -746,6 +746,8 @@ smgrreadv(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
* responsible for pgaio_result_report() to mirror that news to the user (if
* the IO results in PGAIO_RS_WARNING) or abort the (sub)transaction (if
* PGAIO_RS_ERROR).
+ * - Under Valgrind, the "buffers" memory may or may not change status to
+ * DEFINED, depending on io_method and concurrent activity.
*/
void
smgrstartreadv(PgAioHandle *ioh,
diff --git a/src/include/storage/aio_internal.h b/src/include/storage/aio_internal.h
index 7f18da2c856..33f27b9fe50 100644
--- a/src/include/storage/aio_internal.h
+++ b/src/include/storage/aio_internal.h
@@ -344,6 +344,7 @@ extern PgAioResult pgaio_io_call_complete_local(PgAioHandle *ioh);
extern void pgaio_io_perform_synchronously(PgAioHandle *ioh);
extern const char *pgaio_io_get_op_name(PgAioHandle *ioh);
extern bool pgaio_io_uses_fd(PgAioHandle *ioh, int fd);
+extern int pgaio_io_get_iovec_length(PgAioHandle *ioh, struct iovec **iov);
/* aio_target.c */
extern bool pgaio_io_can_reopen(PgAioHandle *ioh);