Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * aio_io.c
4 : : * AIO - Low Level IO Handling
5 : : *
6 : : * Functions related to associating IO operations to IO Handles and IO-method
7 : : * independent support functions for actually performing IO.
8 : : *
9 : : *
10 : : * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
11 : : * Portions Copyright (c) 1994, Regents of the University of California
12 : : *
13 : : * IDENTIFICATION
14 : : * src/backend/storage/aio/aio_io.c
15 : : *
16 : : *-------------------------------------------------------------------------
17 : : */
18 : :
19 : : #include "postgres.h"
20 : :
21 : : #include "miscadmin.h"
22 : : #include "storage/aio.h"
23 : : #include "storage/aio_internal.h"
24 : : #include "storage/fd.h"
25 : : #include "utils/wait_event.h"
26 : :
27 : :
28 : : static void pgaio_io_before_start(PgAioHandle *ioh);
29 : :
30 : :
31 : :
32 : : /* --------------------------------------------------------------------------------
33 : : * Public IO related functions operating on IO Handles
34 : : * --------------------------------------------------------------------------------
35 : : */
36 : :
37 : : /*
38 : : * Scatter/gather IO needs to associate an iovec with the Handle. To support
39 : : * worker mode this data needs to be in shared memory.
40 : : */
41 : : int
173 andres@anarazel.de 42 :CBC 1245616 : pgaio_io_get_iovec(PgAioHandle *ioh, struct iovec **iov)
43 : : {
44 [ - + ]: 1245616 : Assert(ioh->state == PGAIO_HS_HANDED_OUT);
45 : :
46 : 1245616 : *iov = &pgaio_ctl->iovecs[ioh->iovec_off];
47 : :
48 : 1245616 : return PG_IOV_MAX;
49 : : }
50 : :
51 : : PgAioOp
52 : 448402 : pgaio_io_get_op(PgAioHandle *ioh)
53 : : {
54 : 448402 : return ioh->op;
55 : : }
56 : :
57 : : PgAioOpData *
58 : 448402 : pgaio_io_get_op_data(PgAioHandle *ioh)
59 : : {
60 : 448402 : return &ioh->op_data;
61 : : }
62 : :
63 : :
64 : :
65 : : /* --------------------------------------------------------------------------------
66 : : * "Start" routines for individual IO operations
67 : : *
68 : : * These are called by the code actually initiating an IO, to associate the IO
69 : : * specific data with an AIO handle.
70 : : *
71 : : * Each of the "start" routines first needs to call pgaio_io_before_start(),
72 : : * then fill IO specific fields in the handle and then finally call
73 : : * pgaio_io_stage().
74 : : * --------------------------------------------------------------------------------
75 : : */
76 : :
77 : : void
164 78 : 1245616 : pgaio_io_start_readv(PgAioHandle *ioh,
79 : : int fd, int iovcnt, uint64 offset)
80 : : {
81 : 1245616 : pgaio_io_before_start(ioh);
82 : :
173 83 : 1245616 : ioh->op_data.read.fd = fd;
84 : 1245616 : ioh->op_data.read.offset = offset;
85 : 1245616 : ioh->op_data.read.iov_length = iovcnt;
86 : :
87 : 1245616 : pgaio_io_stage(ioh, PGAIO_OP_READV);
88 : 1245616 : }
89 : :
90 : : void
164 andres@anarazel.de 91 :UBC 0 : pgaio_io_start_writev(PgAioHandle *ioh,
92 : : int fd, int iovcnt, uint64 offset)
93 : : {
94 : 0 : pgaio_io_before_start(ioh);
95 : :
173 96 : 0 : ioh->op_data.write.fd = fd;
97 : 0 : ioh->op_data.write.offset = offset;
98 : 0 : ioh->op_data.write.iov_length = iovcnt;
99 : :
100 : 0 : pgaio_io_stage(ioh, PGAIO_OP_WRITEV);
101 : 0 : }
102 : :
103 : :
104 : :
105 : : /* --------------------------------------------------------------------------------
106 : : * Internal IO related functions operating on IO Handles
107 : : * --------------------------------------------------------------------------------
108 : : */
109 : :
110 : : /*
111 : : * Execute IO operation synchronously. This is implemented here, not in
112 : : * method_sync.c, because other IO methods also might use it / fall back to
113 : : * it.
114 : : */
115 : : void
173 andres@anarazel.de 116 :CBC 1141741 : pgaio_io_perform_synchronously(PgAioHandle *ioh)
117 : : {
118 : 1141741 : ssize_t result = 0;
119 : 1141741 : struct iovec *iov = &pgaio_ctl->iovecs[ioh->iovec_off];
120 : :
121 : 1141741 : START_CRIT_SECTION();
122 : :
123 : : /* Perform IO. */
10 124 [ + - - - ]: 1141741 : switch ((PgAioOp) ioh->op)
125 : : {
173 126 : 1141741 : case PGAIO_OP_READV:
127 : 1141741 : pgstat_report_wait_start(WAIT_EVENT_DATA_FILE_READ);
128 : 1141741 : result = pg_preadv(ioh->op_data.read.fd, iov,
129 : 1141741 : ioh->op_data.read.iov_length,
130 : 1141741 : ioh->op_data.read.offset);
131 : 1141741 : pgstat_report_wait_end();
132 : 1141741 : break;
173 andres@anarazel.de 133 :UBC 0 : case PGAIO_OP_WRITEV:
134 : 0 : pgstat_report_wait_start(WAIT_EVENT_DATA_FILE_WRITE);
135 : 0 : result = pg_pwritev(ioh->op_data.write.fd, iov,
136 : 0 : ioh->op_data.write.iov_length,
137 : 0 : ioh->op_data.write.offset);
138 : 0 : pgstat_report_wait_end();
139 : 0 : break;
140 : 0 : case PGAIO_OP_INVALID:
141 [ # # ]: 0 : elog(ERROR, "trying to execute invalid IO operation");
142 : : }
143 : :
173 andres@anarazel.de 144 [ - + ]:CBC 1141741 : ioh->result = result < 0 ? -errno : result;
145 : :
146 : 1141741 : pgaio_io_process_completion(ioh, ioh->result);
147 : :
148 [ - + ]: 1141741 : END_CRIT_SECTION();
149 : 1141741 : }
150 : :
151 : : /*
152 : : * Helper function to be called by IO operation preparation functions, before
153 : : * any data in the handle is set. Mostly to centralize assertions.
154 : : */
155 : : static void
164 156 : 1245616 : pgaio_io_before_start(PgAioHandle *ioh)
157 : : {
173 158 [ - + ]: 1245616 : Assert(ioh->state == PGAIO_HS_HANDED_OUT);
159 [ - + ]: 1245616 : Assert(pgaio_my_backend->handed_out_io == ioh);
160 [ - + ]: 1245616 : Assert(pgaio_io_has_target(ioh));
161 [ - + ]: 1245616 : Assert(ioh->op == PGAIO_OP_INVALID);
162 : :
163 : : /*
164 : : * Otherwise the FDs referenced by the IO could be closed due to interrupt
165 : : * processing.
166 : : */
164 167 [ - + - - : 1245616 : Assert(!INTERRUPTS_CAN_BE_PROCESSED());
- - ]
173 168 : 1245616 : }
169 : :
170 : : /*
171 : : * Could be made part of the public interface, but it's not clear there's
172 : : * really a use case for that.
173 : : */
174 : : const char *
175 : 11006 : pgaio_io_get_op_name(PgAioHandle *ioh)
176 : : {
177 [ - + ]: 11006 : Assert(ioh->op >= 0 && ioh->op < PGAIO_OP_COUNT);
178 : :
10 179 [ + + - - ]: 11006 : switch ((PgAioOp) ioh->op)
180 : : {
173 181 : 3751 : case PGAIO_OP_INVALID:
182 : 3751 : return "invalid";
183 : 7255 : case PGAIO_OP_READV:
108 michael@paquier.xyz 184 : 7255 : return "readv";
173 andres@anarazel.de 185 :UBC 0 : case PGAIO_OP_WRITEV:
108 michael@paquier.xyz 186 : 0 : return "writev";
187 : : }
188 : :
173 andres@anarazel.de 189 : 0 : return NULL; /* silence compiler */
190 : : }
191 : :
192 : : /*
193 : : * Used to determine if an IO needs to be waited upon before the file
194 : : * descriptor can be closed.
195 : : */
196 : : bool
172 andres@anarazel.de 197 :CBC 9 : pgaio_io_uses_fd(PgAioHandle *ioh, int fd)
198 : : {
199 [ - + ]: 9 : Assert(ioh->state >= PGAIO_HS_DEFINED);
200 : :
10 201 [ + - - - ]: 9 : switch ((PgAioOp) ioh->op)
202 : : {
172 203 : 9 : case PGAIO_OP_READV:
204 : 9 : return ioh->op_data.read.fd == fd;
172 andres@anarazel.de 205 :UBC 0 : case PGAIO_OP_WRITEV:
206 : 0 : return ioh->op_data.write.fd == fd;
207 : 0 : case PGAIO_OP_INVALID:
208 : 0 : return false;
209 : : }
210 : :
211 : 0 : return false; /* silence compiler */
212 : : }
213 : :
214 : : /*
215 : : * Return the iovec and its length. Currently only expected to be used by
216 : : * debugging infrastructure
217 : : */
218 : : int
152 219 : 0 : pgaio_io_get_iovec_length(PgAioHandle *ioh, struct iovec **iov)
220 : : {
221 [ # # ]: 0 : Assert(ioh->state >= PGAIO_HS_DEFINED);
222 : :
223 : 0 : *iov = &pgaio_ctl->iovecs[ioh->iovec_off];
224 : :
10 225 [ # # # ]: 0 : switch ((PgAioOp) ioh->op)
226 : : {
152 227 : 0 : case PGAIO_OP_READV:
228 : 0 : return ioh->op_data.read.iov_length;
229 : 0 : case PGAIO_OP_WRITEV:
230 : 0 : return ioh->op_data.write.iov_length;
231 : 0 : default:
232 : 0 : pg_unreachable();
233 : : return 0;
234 : : }
235 : : }
|