|
5 | 5 | //! C headers: [`include/linux/mm.h`](../../include/linux/mm.h)
|
6 | 6 |
|
7 | 7 | use crate::error::{code::*, Result};
|
| 8 | +use crate::page::Page; |
8 | 9 | use crate::types::{ARef, AlwaysRefCounted, Opaque, ScopeGuard};
|
| 10 | +use core::mem::ManuallyDrop; |
9 | 11 | use core::{cmp::min, ptr};
|
10 | 12 |
|
11 | 13 | /// Wraps the kernel's `struct folio`.
|
@@ -88,6 +90,59 @@ impl UniqueFolio {
|
88 | 90 |
|
89 | 91 | Ok(MapGuard { data, page })
|
90 | 92 | }
|
| 93 | + |
| 94 | + /// Map a page into memory and run a function with a shared slice pointing |
| 95 | + /// to a mapped page. |
| 96 | + /// |
| 97 | + /// The page is mapped for the duration fo the function. |
| 98 | + pub fn with_slice_into_page<T>( |
| 99 | + &self, |
| 100 | + page_index: usize, |
| 101 | + f: impl FnOnce(&[u8]) -> Result<T>, |
| 102 | + ) -> Result<T> { |
| 103 | + if page_index >= self.0.size() / bindings::PAGE_SIZE { |
| 104 | + return Err(EDOM); |
| 105 | + } |
| 106 | + |
| 107 | + // SAFETY: We just checked that the index is within bounds of the folio. |
| 108 | + let page_ptr = unsafe { bindings::folio_page(self.0 .0.get(), page_index) }; |
| 109 | + |
| 110 | + ManuallyDrop::new( |
| 111 | + // SAFETY: `page_ptr` points to a page that we own. We take care not |
| 112 | + // free the page when we are done with it, by wrapping in |
| 113 | + // `ManuallyDrop`. We also do no mutable access through this `Page`. |
| 114 | + unsafe { Page::from_raw(page_ptr) }, |
| 115 | + ) |
| 116 | + .with_slice_into_page(f) |
| 117 | + } |
| 118 | + |
| 119 | + /// Map a page into memory and run a function with a mutable slice pointing |
| 120 | + /// to a mapped page. |
| 121 | + /// |
| 122 | + /// The page is mapped for the duration fo the function. |
| 123 | + pub fn with_slice_into_page_mut<T>( |
| 124 | + &mut self, |
| 125 | + page_index: usize, |
| 126 | + f: impl FnOnce(&mut [u8]) -> Result<T>, |
| 127 | + ) -> Result<T> { |
| 128 | + if page_index >= self.0.size() / bindings::PAGE_SIZE { |
| 129 | + return Err(EDOM); |
| 130 | + } |
| 131 | + |
| 132 | + // SAFETY: We just checked that the index is within bounds of the folio. |
| 133 | + let page_ptr = unsafe { bindings::folio_page(self.0 .0.get(), page_index) }; |
| 134 | + |
| 135 | + ManuallyDrop::new( |
| 136 | + // SAFETY: `page_ptr` points to a page that we own. By existence of |
| 137 | + // `&mut self` we have exclusive access to the page. We take care |
| 138 | + // not free the page when we are done with it, by wrapping in |
| 139 | + // `ManuallyDrop`. We forget the page as soone as we are donw with |
| 140 | + // our access so as to allow no further mutable access through the |
| 141 | + // `Page` we are creating. |
| 142 | + unsafe { Page::from_raw(page_ptr) }, |
| 143 | + ) |
| 144 | + .with_slice_into_page_mut(f) |
| 145 | + } |
91 | 146 | }
|
92 | 147 |
|
93 | 148 | /// A mapped [`UniqueFolio`].
|
|
0 commit comments