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" @@ -529,6 +530,24 @@ IoWorkerMain(const void *startup_data, size_t startup_data_len) error_errno = 0; 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. 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);