1use super::drivers::RangeBlockedGuard;
8use crate::io_buffers::{IoBuffer, IoVector, IoVectorMut, IoVectorTrait};
9use crate::Storage;
10use maybe_async::maybe_async;
11use std::ops::Range;
12use std::{cmp, io};
13use tracing::trace;
14
15#[maybe_async(AFIT)]
19pub trait StorageExt: Storage {
20 #[allow(async_fn_in_trait)] async fn readv(&self, bufv: IoVectorMut<'_>, offset: u64) -> io::Result<()>;
29
30 #[allow(async_fn_in_trait)] async fn writev(&self, bufv: IoVector<'_>, offset: u64) -> io::Result<()>;
42
43 #[allow(async_fn_in_trait)] async fn read<'a>(&'a self, buf: impl Into<IoVectorMut<'a>>, offset: u64) -> io::Result<()>;
52
53 #[allow(async_fn_in_trait)] async fn write<'a>(&'a self, buf: impl Into<IoVector<'a>>, offset: u64) -> io::Result<()>;
65
66 #[allow(async_fn_in_trait)] async fn write_zeroes(&self, offset: u64, length: u64) -> io::Result<()>;
69
70 #[allow(async_fn_in_trait)] async fn write_allocated_zeroes(&self, offset: u64, length: u64) -> io::Result<()>;
73
74 #[allow(async_fn_in_trait)] async fn discard(&self, offset: u64, length: u64) -> io::Result<()>;
80
81 #[allow(async_fn_in_trait)] async fn weak_write_blocker(&self, range: Range<u64>) -> RangeBlockedGuard<'_>;
88
89 #[allow(async_fn_in_trait)] async fn strong_write_blocker(&self, range: Range<u64>) -> RangeBlockedGuard<'_>;
95}
96
97#[maybe_async(AFIT)]
98impl<S: Storage> StorageExt for S {
99 async fn readv(&self, mut bufv: IoVectorMut<'_>, offset: u64) -> io::Result<()> {
100 if bufv.is_empty() {
101 return Ok(());
102 }
103
104 let unpadded_end = offset
105 .checked_add(bufv.len())
106 .ok_or_else(|| io::Error::other("Read wrap-around"))?;
107
108 let mem_align = self.mem_align();
109 let req_align = self.req_align();
110
111 if is_aligned(&bufv, offset, mem_align, req_align) {
112 return unsafe { self.pure_readv(bufv, offset) }.await;
114 }
115
116 trace!(
117 "Unaligned read: 0x{offset:x} + {} (size: {:#x})",
118 bufv.len(),
119 self.size().unwrap()
120 );
121
122 let req_align_mask = req_align as u64 - 1;
123 let len_align_mask = req_align_mask | (mem_align as u64 - 1);
125 debug_assert!((len_align_mask + 1).is_multiple_of(req_align as u64));
126
127 let padded_offset = offset & !req_align_mask;
128 let padded_end = unpadded_end
131 .checked_add(req_align_mask)
132 .ok_or_else(|| io::Error::other("Read wrap-around"))?
133 & !req_align_mask;
134 let padded_len = (padded_end - padded_offset + len_align_mask) & !(len_align_mask);
136 let padded_end = padded_offset
137 .checked_add(padded_len)
138 .ok_or_else(|| io::Error::other("Read wrap-around"))?;
139
140 let padded_len: usize = (padded_end - padded_offset)
141 .try_into()
142 .map_err(|e| io::Error::other(format!("Cannot realign read: {e}")))?;
143
144 trace!("Padded read: {padded_offset:#x} + {padded_len}");
145
146 let mut bounce_buf = IoBuffer::new(padded_len, mem_align)?;
147
148 unsafe { self.pure_readv(bounce_buf.as_mut().into(), padded_offset) }.await?;
150
151 let in_buf_ofs = (offset - padded_offset) as usize;
152 let in_buf_end = (unpadded_end - padded_offset) as usize;
154
155 bufv.copy_from_slice(bounce_buf.as_ref_range(in_buf_ofs..in_buf_end).into_slice());
156
157 Ok(())
158 }
159
160 async fn writev(&self, bufv: IoVector<'_>, offset: u64) -> io::Result<()> {
161 if bufv.is_empty() {
162 return Ok(());
163 }
164
165 let unpadded_end = offset
166 .checked_add(bufv.len())
167 .ok_or_else(|| io::Error::other("Write wrap-around"))?;
168
169 let mem_align = self.mem_align();
170 let req_align = self.req_align();
171
172 if is_aligned(&bufv, offset, mem_align, req_align) {
173 let _sw_guard = self.weak_write_blocker(offset..unpadded_end).await;
174
175 return unsafe { self.pure_writev(bufv, offset) }.await;
177 }
178
179 trace!(
180 "Unaligned write: {offset:#x} + {} (size: {:#x})",
181 bufv.len(),
182 self.size().unwrap()
183 );
184
185 let req_align_mask = req_align - 1;
186 let len_align_mask = req_align_mask | (mem_align - 1);
188 let len_align = req_align_mask + 1;
189 debug_assert!(len_align.is_multiple_of(req_align));
190
191 let padded_offset = offset & !(req_align_mask as u64);
192 let padded_end = unpadded_end
196 .checked_add(req_align_mask as u64)
197 .ok_or_else(|| io::Error::other("Write wrap-around"))?
198 & !(req_align_mask as u64);
199 let padded_len =
201 (padded_end - padded_offset + len_align_mask as u64) & !(len_align_mask as u64);
202 let padded_end = padded_offset
203 .checked_add(padded_len)
204 .ok_or_else(|| io::Error::other("Write wrap-around"))?;
205
206 let padded_len: usize = (padded_end - padded_offset)
207 .try_into()
208 .map_err(|e| io::Error::other(format!("Cannot realign write: {e}")))?;
209
210 trace!("Padded write: {padded_offset:#x} + {padded_len}");
211
212 let mut bounce_buf = IoBuffer::new(padded_len, mem_align)?;
213 assert!(padded_len >= len_align && padded_len & len_align_mask == 0);
214
215 let _sw_guard = self.strong_write_blocker(padded_offset..padded_end).await;
222
223 let in_buf_ofs = (offset - padded_offset) as usize;
224 let in_buf_end = (unpadded_end - padded_offset) as usize;
226
227 let head_len = in_buf_ofs;
230 let aligned_head_len = (head_len + len_align_mask) & !len_align_mask;
231
232 let tail_len = padded_len - in_buf_end;
233 let aligned_tail_len = (tail_len + len_align_mask) & !len_align_mask;
234
235 if aligned_head_len + aligned_tail_len == padded_len {
236 unsafe { self.pure_readv(bounce_buf.as_mut().into(), padded_offset) }.await?;
239 } else {
240 if aligned_head_len > 0 {
241 let head_bufv = bounce_buf.as_mut_range(0..aligned_head_len).into();
242 unsafe { self.pure_readv(head_bufv, padded_offset) }.await?;
244 }
245 if aligned_tail_len > 0 {
246 let tail_start = padded_len - aligned_tail_len;
247 let tail_bufv = bounce_buf.as_mut_range(tail_start..padded_len).into();
248 unsafe { self.pure_readv(tail_bufv, padded_offset + tail_start as u64) }.await?;
250 }
251 }
252
253 bufv.copy_into_slice(bounce_buf.as_mut_range(in_buf_ofs..in_buf_end).into_slice());
255
256 unsafe { self.pure_writev(bounce_buf.as_ref().into(), padded_offset) }.await
259 }
260
261 async fn read<'a>(&'a self, buf: impl Into<IoVectorMut<'a>>, offset: u64) -> io::Result<()> {
262 self.readv(buf.into(), offset).await
263 }
264
265 async fn write<'a>(&'a self, buf: impl Into<IoVector<'a>>, offset: u64) -> io::Result<()> {
266 self.writev(buf.into(), offset).await
267 }
268
269 async fn write_zeroes(&self, offset: u64, length: u64) -> io::Result<()> {
270 write_efficient_zeroes(self, offset, length, false).await
271 }
272
273 async fn write_allocated_zeroes(&self, offset: u64, length: u64) -> io::Result<()> {
274 write_efficient_zeroes(self, offset, length, true).await
275 }
276
277 async fn discard(&self, offset: u64, length: u64) -> io::Result<()> {
278 let discard_align = self.discard_align();
279 debug_assert!(discard_align.is_power_of_two());
280 let align_mask = discard_align as u64 - 1;
281
282 let unaligned_end = offset
283 .checked_add(length)
284 .ok_or_else(|| io::Error::other("Discard wrap-around"))?;
285 let aligned_offset = offset
286 .checked_add(align_mask)
287 .ok_or_else(|| io::Error::other("Discard wrap-around"))?
288 & !align_mask;
289 let aligned_end = unaligned_end & !align_mask;
290
291 if aligned_end > aligned_offset {
292 let _sw_guard = self.weak_write_blocker(aligned_offset..aligned_end).await;
293 let aligned_len = aligned_end - aligned_offset;
294 if let Err(err) = unsafe { self.pure_discard(aligned_offset, aligned_len) }.await {
296 if err.kind() != io::ErrorKind::Unsupported {
301 return Err(err);
302 }
303 }
304 }
305
306 Ok(())
309 }
310
311 async fn weak_write_blocker(&self, range: Range<u64>) -> RangeBlockedGuard<'_> {
312 self.get_storage_helper().weak_write_blocker(range).await
313 }
314
315 async fn strong_write_blocker(&self, range: Range<u64>) -> RangeBlockedGuard<'_> {
316 self.get_storage_helper().strong_write_blocker(range).await
317 }
318}
319
320fn is_aligned<V: IoVectorTrait>(bufv: &V, offset: u64, mem_align: usize, req_align: usize) -> bool {
322 debug_assert!(mem_align.is_power_of_two() && req_align.is_power_of_two());
323
324 let req_align_mask = req_align as u64 - 1;
325
326 if offset & req_align_mask != 0 {
327 false
328 } else if bufv.len() & req_align_mask == 0 {
329 bufv.is_aligned(mem_align, req_align)
330 } else {
331 false
332 }
333}
334
335#[maybe_async]
340pub(crate) async fn write_full_zeroes<S: StorageExt>(
341 storage: S,
342 mut offset: u64,
343 mut length: u64,
344) -> io::Result<()> {
345 let req_align = storage.req_align();
346 let req_align_mask = (req_align - 1) as u64;
347
348 let mem_align = storage.mem_align();
349 let max_chunk_len = cmp::max(cmp::max(req_align, mem_align), 1048576) as u64;
350 let buflen = cmp::min(length, max_chunk_len) as usize;
351 let mut buf = IoBuffer::new(buflen, storage.mem_align())?;
352 buf.as_mut().into_slice().fill(0);
353
354 while length > 0 {
355 let mut chunk_length = cmp::min(length, max_chunk_len) as usize;
356 if offset & req_align_mask != 0 {
357 chunk_length = cmp::min(chunk_length, req_align - (offset & req_align_mask) as usize);
358 }
359 storage
360 .write(buf.as_ref_range(0..chunk_length), offset)
361 .await?;
362 offset += chunk_length as u64;
363 length -= chunk_length as u64;
364 }
365
366 Ok(())
367}
368
369#[maybe_async]
379pub(crate) async fn write_efficient_zeroes<S: StorageExt>(
380 storage: S,
381 offset: u64,
382 length: u64,
383 allocate: bool,
384) -> io::Result<()> {
385 if length == 0 {
386 return Ok(());
387 }
388
389 let zero_align = storage.zero_align();
390 debug_assert!(zero_align.is_power_of_two());
391 let align_mask = zero_align as u64 - 1;
392
393 let unaligned_end = offset
394 .checked_add(length)
395 .ok_or_else(|| io::Error::other("Zero-write wrap-around"))?;
396 let aligned_offset = offset
397 .checked_add(align_mask)
398 .ok_or_else(|| io::Error::other("Zero-write wrap-around"))?
399 & !align_mask;
400 let aligned_end = unaligned_end & !align_mask;
401
402 if aligned_end > aligned_offset {
403 let result = {
404 let _sw_guard = storage
405 .weak_write_blocker(aligned_offset..aligned_end)
406 .await;
407 if allocate {
409 unsafe {
410 storage
411 .pure_write_allocated_zeroes(aligned_offset, aligned_end - aligned_offset)
412 }
413 .await
414 } else {
415 unsafe { storage.pure_write_zeroes(aligned_offset, aligned_end - aligned_offset) }
416 .await
417 }
418 };
419 if let Err(err) = result {
420 return if err.kind() == io::ErrorKind::Unsupported {
421 write_full_zeroes(storage, offset, length).await
422 } else {
423 Err(err)
424 };
425 }
426 }
427
428 let zero_buf = if aligned_offset > offset || aligned_end < unaligned_end {
429 let buflen = if aligned_offset >= aligned_end {
430 unaligned_end - offset
431 } else {
432 cmp::max(aligned_offset - offset, unaligned_end - aligned_end)
433 };
434 let mut buf = IoBuffer::new(buflen as usize, storage.mem_align())?;
435 buf.as_mut().into_slice().fill(0);
436 Some(buf)
437 } else {
438 None
439 };
440
441 if aligned_offset >= aligned_end {
442 let buf = zero_buf
443 .as_ref()
444 .unwrap()
445 .as_ref_range(0..((unaligned_end - offset) as usize));
446 storage.write(buf, offset).await?;
447 } else {
448 if aligned_offset > offset {
449 assert!(aligned_offset <= unaligned_end);
450 let buf = zero_buf
451 .as_ref()
452 .unwrap()
453 .as_ref_range(0..((aligned_offset - offset) as usize));
454 storage.write(buf, offset).await?;
455 }
456 if aligned_end < unaligned_end {
457 assert!(aligned_end >= offset);
458 let buf = zero_buf
459 .as_ref()
460 .unwrap()
461 .as_ref_range(0..((unaligned_end - aligned_end) as usize));
462 storage.write(buf, aligned_end).await?;
463 }
464 }
465
466 Ok(())
467}
468
469#[cfg(test)]
470mod tests {
471 use super::*;
472 use crate::test::mem_storage::{MemStorage, MemStorageState};
473 use std::sync::Arc;
474
475 #[maybe_async::test(feature = "sync", async(feature = "async", tokio::test))]
477 async fn readv_writev_overflow() {
478 let state = Arc::new(MemStorageState::default());
479 let mut buf = vec![0u8; 8192];
480
481 let mem = MemStorage::new(Arc::clone(&state), false);
485 let offset = u64::MAX - 4095;
486 let result = mem.read(&mut buf[..], offset).await;
487 assert!(result.is_err());
488 let result = mem.write(&buf[..], offset).await;
489 assert!(result.is_err());
490
491 let mem = MemStorage::new(state, false).with_align(4096);
493 let offset = u64::MAX - 10;
494 let result = mem.read(&mut buf[..100], offset).await;
495 assert!(result.is_err());
496 let result = mem.write(&buf[..100], offset).await;
497 assert!(result.is_err());
498
499 let offset = u64::MAX - 100;
501 let result = mem.read(&mut buf[..50], offset).await;
502 assert!(result.is_err());
503 let result = mem.write(&buf[..50], offset).await;
504 assert!(result.is_err());
505 }
506
507 #[maybe_async::test(feature = "sync", async(feature = "async", tokio::test))]
510 async fn discard_write_zeroes_overflow() {
511 let mem = MemStorage::new(Arc::new(MemStorageState::default()), false).with_align(4096);
513
514 let offset = u64::MAX - 10;
516 let result = mem.discard(offset, 5).await;
517 assert!(result.is_err());
518 let result = mem.write_zeroes(offset, 5).await;
519 assert!(result.is_err());
520 let result = mem.write_allocated_zeroes(offset, 5).await;
521 assert!(result.is_err());
522 }
523}