Submit a write SQE and wait for the CQE. ## O_DIRECT alignment invariant When `use_direct_io` is true, the submission slice (`data`) is zero-padded up to the alignment boundary via `as_aligned_slice`. The kernel writes exactly `data.len()` bytes, so `file_offset` MUST advance by `data.len()` — the padded length, not the unpadded buffer content length. Advancing by the unpadded length leaves the
(&mut self)
| 216 | /// write with `-EINVAL`. Mirrors the precedent set by |
| 217 | /// `WalWriter::flush_buffer`. |
| 218 | fn submit_and_wait_write(&mut self) -> Result<()> { |
| 219 | if self.buffer.is_empty() { |
| 220 | return Ok(()); |
| 221 | } |
| 222 | |
| 223 | let data = if self.config.use_direct_io { |
| 224 | self.buffer.as_aligned_slice() |
| 225 | } else { |
| 226 | self.buffer.as_slice() |
| 227 | }; |
| 228 | let write_len = data.len() as u64; |
| 229 | |
| 230 | let fd = types::Fd(self.file.as_raw_fd()); |
| 231 | let write_op = opcode::Write::new(fd, data.as_ptr(), data.len() as u32) |
| 232 | .offset(self.file_offset) |
| 233 | .build() |
| 234 | .user_data(0x01); |
| 235 | |
| 236 | // SAFETY: write_op holds a raw pointer to `data` (which borrows self.buffer). |
| 237 | // The buffer remains valid and unmodified until submit_and_wait(1) returns |
| 238 | // with the CQE, after which self.buffer.clear() is called. Do NOT pipeline |
| 239 | // submissions without ensuring the buffer outlives the SQE. |
| 240 | unsafe { |
| 241 | self.ring |
| 242 | .submission() |
| 243 | .push(&write_op) |
| 244 | .map_err(|_| WalError::Io(std::io::Error::other("io_uring SQ full")))?; |
| 245 | } |
| 246 | |
| 247 | self.ring.submit_and_wait(1).map_err(WalError::Io)?; |
| 248 | |
| 249 | // Check completion. |
| 250 | let cqe = |
| 251 | self.ring.completion().next().ok_or_else(|| { |
| 252 | WalError::Io(std::io::Error::other("io_uring: no CQE after write")) |
| 253 | })?; |
| 254 | |
| 255 | if cqe.result() < 0 { |
| 256 | return Err(WalError::Io(std::io::Error::from_raw_os_error( |
| 257 | -cqe.result(), |
| 258 | ))); |
| 259 | } |
| 260 | |
| 261 | // See the O_DIRECT alignment invariant on this function's doc comment. |
| 262 | self.file_offset += write_len; |
| 263 | self.buffer.clear(); |
| 264 | Ok(()) |
| 265 | } |
| 266 | |
| 267 | /// Submit an fsync SQE and wait for the CQE. |
| 268 | fn submit_and_wait_fsync(&mut self) -> Result<()> { |