| 1 | |
| 2 |
|
| 3 | |
| 4 |
|
| 5 | |
| 6 | |
| 7 |
|
| 8 | |
| 9 | |
| 10 | |
| 11 | |
| 12 | |
| 13 | |
| 14 | |
| 15 |
|
| 16 | use crate::AssertSync;
|
| 17 |
|
| 18 | use core::{
|
| 19 | marker::PhantomPinned,
|
| 20 | mem::{size_of, size_of_val, MaybeUninit},
|
| 21 | ptr,
|
| 22 | };
|
| 23 |
|
| 24 | use kernel::{
|
| 25 | bindings,
|
| 26 | error::Result,
|
| 27 | ffi::{c_ulong, c_void},
|
| 28 | mm::{virt, Mm, MmWithUser},
|
| 29 | new_mutex, new_spinlock,
|
| 30 | page::{Page, PAGE_SHIFT, PAGE_SIZE},
|
| 31 | prelude::*,
|
| 32 | str::CStr,
|
| 33 | sync::{aref::ARef, Mutex, SpinLock},
|
| 34 | task::Pid,
|
| 35 | transmute::FromBytes,
|
| 36 | types::Opaque,
|
| 37 | uaccess::UserSliceReader,
|
| 38 | };
|
| 39 |
|
| 40 | |
| 41 | |
| 42 | |
| 43 | #[repr(C)]
|
| 44 | pub(crate) struct Shrinker {
|
| 45 | inner: Opaque<*mut bindings::shrinker>,
|
| 46 | list_lru: Opaque<bindings::list_lru>,
|
| 47 | }
|
| 48 |
|
| 49 | |
| 50 | unsafe impl Send for Shrinker {}
|
| 51 | |
| 52 | unsafe impl Sync for Shrinker {}
|
| 53 |
|
| 54 | impl Shrinker {
|
| 55 | |
| 56 | |
| 57 | |
| 58 | |
| 59 | |
| 60 | |
| 61 | pub(crate) const unsafe fn new() -> Self {
|
| 62 | Self {
|
| 63 | inner: Opaque::uninit(),
|
| 64 | list_lru: Opaque::uninit(),
|
| 65 | }
|
| 66 | }
|
| 67 |
|
| 68 | |
| 69 | pub(crate) fn register(&'static self, name: &CStr) -> Result<()> {
|
| 70 | |
| 71 | unsafe {
|
| 72 | self.inner.get().write(ptr::null_mut());
|
| 73 | self.list_lru.get().write_bytes(0, 1);
|
| 74 | }
|
| 75 |
|
| 76 | |
| 77 | let ret = unsafe { bindings::__list_lru_init(self.list_lru.get(), false, ptr::null_mut()) };
|
| 78 | if ret != 0 {
|
| 79 | return Err(Error::from_errno(ret));
|
| 80 | }
|
| 81 |
|
| 82 | |
| 83 | let shrinker = unsafe { bindings::shrinker_alloc(0, name.as_char_ptr()) };
|
| 84 | if shrinker.is_null() {
|
| 85 | |
| 86 | unsafe { bindings::list_lru_destroy(self.list_lru.get()) };
|
| 87 | return Err(Error::from_errno(ret));
|
| 88 | }
|
| 89 |
|
| 90 | |
| 91 | |
| 92 | unsafe {
|
| 93 | (&raw mut (*shrinker).count_objects).write(Some(rust_shrink_count));
|
| 94 | (&raw mut (*shrinker).scan_objects).write(Some(rust_shrink_scan));
|
| 95 | (&raw mut (*shrinker).private_data).write(self.list_lru.get().cast());
|
| 96 | }
|
| 97 |
|
| 98 | |
| 99 | unsafe { bindings::shrinker_register(shrinker) };
|
| 100 |
|
| 101 | |
| 102 | unsafe { self.inner.get().write(shrinker) };
|
| 103 |
|
| 104 | Ok(())
|
| 105 | }
|
| 106 | }
|
| 107 |
|
| 108 | |
| 109 | |
| 110 | |
| 111 | |
| 112 | |
| 113 | |
| 114 | |
| 115 | |
| 116 | |
| 117 | |
| 118 | |
| 119 | |
| 120 | |
| 121 | |
| 122 | |
| 123 | |
| 124 | |
| 125 | |
| 126 | |
| 127 | #[pin_data(PinnedDrop)]
|
| 128 | pub(crate) struct ShrinkablePageRange {
|
| 129 | |
| 130 | shrinker: &'static Shrinker,
|
| 131 | |
| 132 | pid: Pid,
|
| 133 | |
| 134 | mm: ARef<Mm>,
|
| 135 | |
| 136 | #[pin]
|
| 137 | mm_lock: Mutex<()>,
|
| 138 | |
| 139 | #[pin]
|
| 140 | lock: SpinLock<Inner>,
|
| 141 |
|
| 142 | |
| 143 | #[pin]
|
| 144 | _pin: PhantomPinned,
|
| 145 | }
|
| 146 |
|
| 147 | |
| 148 | static BINDER_VM_OPS: AssertSync<bindings::vm_operations_struct> = AssertSync(pin_init::zeroed());
|
| 149 |
|
| 150 | |
| 151 | |
| 152 | fn check_vma(vma: &virt::VmaRef, owner: *const ShrinkablePageRange) -> Option<&virt::VmaMixedMap> {
|
| 153 | |
| 154 | let vm_ops = unsafe { (*vma.as_ptr()).vm_ops };
|
| 155 | if !ptr::eq(vm_ops, &BINDER_VM_OPS.0) {
|
| 156 | return None;
|
| 157 | }
|
| 158 |
|
| 159 | |
| 160 | let vm_private_data = unsafe { (*vma.as_ptr()).vm_private_data };
|
| 161 | |
| 162 | |
| 163 | |
| 164 | if !ptr::eq(vm_private_data, owner.cast()) {
|
| 165 | return None;
|
| 166 | }
|
| 167 |
|
| 168 | vma.as_mixedmap_vma()
|
| 169 | }
|
| 170 |
|
| 171 | struct Inner {
|
| 172 | |
| 173 | |
| 174 | |
| 175 | |
| 176 | pages: *mut PageInfo,
|
| 177 | |
| 178 | size: usize,
|
| 179 | |
| 180 | vma_addr: usize,
|
| 181 | }
|
| 182 |
|
| 183 | |
| 184 | unsafe impl Send for Inner {}
|
| 185 |
|
| 186 | type StableMmGuard =
|
| 187 | kernel::sync::lock::Guard<'static, (), kernel::sync::lock::mutex::MutexBackend>;
|
| 188 |
|
| 189 | |
| 190 | |
| 191 | |
| 192 | |
| 193 | |
| 194 | |
| 195 | |
| 196 | |
| 197 | |
| 198 | #[repr(C)]
|
| 199 | struct PageInfo {
|
| 200 | lru: bindings::list_head,
|
| 201 | page: Option<Page>,
|
| 202 | range: *const ShrinkablePageRange,
|
| 203 | }
|
| 204 |
|
| 205 | impl PageInfo {
|
| 206 | |
| 207 | |
| 208 | |
| 209 | unsafe fn set_page(me: *mut PageInfo, page: Page) {
|
| 210 | |
| 211 | let ptr = unsafe { &raw mut (*me).page };
|
| 212 |
|
| 213 | |
| 214 | if unsafe { (*ptr).is_some() } {
|
| 215 | pr_err!("set_page called when there is already a page");
|
| 216 | |
| 217 | unsafe { ptr::drop_in_place(ptr) };
|
| 218 | }
|
| 219 |
|
| 220 | |
| 221 | unsafe { ptr::write(ptr, Some(page)) };
|
| 222 | }
|
| 223 |
|
| 224 | |
| 225 | |
| 226 | |
| 227 | unsafe fn get_page<'a>(me: *const PageInfo) -> Option<&'a Page> {
|
| 228 | |
| 229 | let ptr = unsafe { &raw const (*me).page };
|
| 230 |
|
| 231 | |
| 232 | unsafe { (*ptr).as_ref() }
|
| 233 | }
|
| 234 |
|
| 235 | |
| 236 | |
| 237 | |
| 238 | unsafe fn take_page(me: *mut PageInfo) -> Option<Page> {
|
| 239 | |
| 240 | let ptr = unsafe { &raw mut (*me).page };
|
| 241 |
|
| 242 | |
| 243 | unsafe { (*ptr).take() }
|
| 244 | }
|
| 245 |
|
| 246 | |
| 247 | |
| 248 | |
| 249 | |
| 250 | |
| 251 | unsafe fn list_lru_add(me: *mut PageInfo, nid: i32, shrinker: &'static Shrinker) {
|
| 252 | |
| 253 | let lru_ptr = unsafe { &raw mut (*me).lru };
|
| 254 | |
| 255 | unsafe { bindings::list_lru_add(shrinker.list_lru.get(), lru_ptr, nid, ptr::null_mut()) };
|
| 256 | }
|
| 257 |
|
| 258 | |
| 259 | |
| 260 | |
| 261 | |
| 262 | |
| 263 | unsafe fn list_lru_del(me: *mut PageInfo, nid: i32, shrinker: &'static Shrinker) {
|
| 264 | |
| 265 | let lru_ptr = unsafe { &raw mut (*me).lru };
|
| 266 | |
| 267 | unsafe { bindings::list_lru_del(shrinker.list_lru.get(), lru_ptr, nid, ptr::null_mut()) };
|
| 268 | }
|
| 269 | }
|
| 270 |
|
| 271 | impl ShrinkablePageRange {
|
| 272 | |
| 273 | pub(crate) fn new(shrinker: &'static Shrinker) -> impl PinInit<Self, Error> {
|
| 274 | try_pin_init!(Self {
|
| 275 | shrinker,
|
| 276 | pid: kernel::current!().pid(),
|
| 277 | mm: ARef::from(&**kernel::current!().mm().ok_or(ESRCH)?),
|
| 278 | mm_lock <- new_mutex!((), "ShrinkablePageRange::mm"),
|
| 279 | lock <- new_spinlock!(Inner {
|
| 280 | pages: ptr::null_mut(),
|
| 281 | size: 0,
|
| 282 | vma_addr: 0,
|
| 283 | }, "ShrinkablePageRange"),
|
| 284 | _pin: PhantomPinned,
|
| 285 | })
|
| 286 | }
|
| 287 |
|
| 288 | pub(crate) fn stable_trylock_mm(&self) -> Option<StableMmGuard> {
|
| 289 | |
| 290 | |
| 291 | |
| 292 | let mm_lock = unsafe { &*ptr::from_ref(&self.mm_lock) };
|
| 293 |
|
| 294 | mm_lock.try_lock()
|
| 295 | }
|
| 296 |
|
| 297 | |
| 298 | pub(crate) fn register_with_vma(&self, vma: &virt::VmaNew) -> Result<usize> {
|
| 299 | let num_bytes = usize::min(vma.end() - vma.start(), bindings::SZ_4M as usize);
|
| 300 | let num_pages = num_bytes >> PAGE_SHIFT;
|
| 301 |
|
| 302 | if !ptr::eq::<Mm>(&*self.mm, &**vma.mm()) {
|
| 303 | pr_debug!("Failed to register with vma: invalid vma->vm_mm");
|
| 304 | return Err(EINVAL);
|
| 305 | }
|
| 306 | if num_pages == 0 {
|
| 307 | pr_debug!("Failed to register with vma: size zero");
|
| 308 | return Err(EINVAL);
|
| 309 | }
|
| 310 |
|
| 311 | let mut pages = KVVec::<PageInfo>::with_capacity(num_pages, GFP_KERNEL)?;
|
| 312 |
|
| 313 | |
| 314 | unsafe {
|
| 315 | let self_ptr = ptr::from_ref(self);
|
| 316 | for i in 0..num_pages {
|
| 317 | let info = pages.as_mut_ptr().add(i);
|
| 318 | (&raw mut (*info).range).write(self_ptr);
|
| 319 | (&raw mut (*info).page).write(None);
|
| 320 | let lru = &raw mut (*info).lru;
|
| 321 | (&raw mut (*lru).next).write(lru);
|
| 322 | (&raw mut (*lru).prev).write(lru);
|
| 323 | }
|
| 324 | }
|
| 325 |
|
| 326 | let mut inner = self.lock.lock();
|
| 327 | if inner.size > 0 {
|
| 328 | pr_debug!("Failed to register with vma: already registered");
|
| 329 | drop(inner);
|
| 330 | return Err(EBUSY);
|
| 331 | }
|
| 332 |
|
| 333 | inner.pages = pages.into_raw_parts().0;
|
| 334 | inner.size = num_pages;
|
| 335 | inner.vma_addr = vma.start();
|
| 336 |
|
| 337 | |
| 338 | |
| 339 | |
| 340 | |
| 341 | unsafe {
|
| 342 | (*vma.as_ptr()).vm_private_data = ptr::from_ref(self).cast_mut().cast::<c_void>()
|
| 343 | };
|
| 344 |
|
| 345 | |
| 346 | |
| 347 | unsafe { (*vma.as_ptr()).vm_ops = &BINDER_VM_OPS.0 };
|
| 348 |
|
| 349 | Ok(num_pages)
|
| 350 | }
|
| 351 |
|
| 352 | |
| 353 | |
| 354 | |
| 355 | pub(crate) fn use_range(&self, start: usize, end: usize) -> Result<()> {
|
| 356 | if start >= end {
|
| 357 | return Ok(());
|
| 358 | }
|
| 359 | let mut inner = self.lock.lock();
|
| 360 | assert!(end <= inner.size);
|
| 361 |
|
| 362 | for i in start..end {
|
| 363 | |
| 364 | let page_info = unsafe { inner.pages.add(i) };
|
| 365 |
|
| 366 | |
| 367 | if let Some(page) = unsafe { PageInfo::get_page(page_info) } {
|
| 368 | |
| 369 | |
| 370 | |
| 371 | |
| 372 | |
| 373 | |
| 374 | |
| 375 | unsafe { PageInfo::list_lru_del(page_info, page.nid(), self.shrinker) };
|
| 376 | } else {
|
| 377 | |
| 378 | drop(inner);
|
| 379 | |
| 380 | match unsafe { self.use_page_slow(i) } {
|
| 381 | Ok(()) => {}
|
| 382 | Err(err) => {
|
| 383 | pr_warn!("Error in use_page_slow: {:?}", err);
|
| 384 | return Err(err);
|
| 385 | }
|
| 386 | }
|
| 387 | inner = self.lock.lock();
|
| 388 | }
|
| 389 | }
|
| 390 | Ok(())
|
| 391 | }
|
| 392 |
|
| 393 | |
| 394 | |
| 395 | |
| 396 | |
| 397 | |
| 398 | |
| 399 | |
| 400 | #[cold]
|
| 401 | unsafe fn use_page_slow(&self, i: usize) -> Result<()> {
|
| 402 | let new_page = Page::alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO)?;
|
| 403 |
|
| 404 | let mm_mutex = self.mm_lock.lock();
|
| 405 | let inner = self.lock.lock();
|
| 406 |
|
| 407 | |
| 408 | let page_info = unsafe { inner.pages.add(i) };
|
| 409 |
|
| 410 | |
| 411 | if let Some(page) = unsafe { PageInfo::get_page(page_info) } {
|
| 412 | |
| 413 | |
| 414 | |
| 415 | |
| 416 | |
| 417 | |
| 418 | |
| 419 | unsafe { PageInfo::list_lru_del(page_info, page.nid(), self.shrinker) };
|
| 420 | return Ok(());
|
| 421 | }
|
| 422 |
|
| 423 | let vma_addr = inner.vma_addr;
|
| 424 | |
| 425 | drop(inner);
|
| 426 |
|
| 427 | |
| 428 | let user_page_addr = vma_addr + (i << PAGE_SHIFT);
|
| 429 |
|
| 430 | |
| 431 | |
| 432 | |
| 433 | |
| 434 | |
| 435 | |
| 436 | |
| 437 | |
| 438 | |
| 439 | |
| 440 | let mm = MmWithUser::into_mmput_async(self.mm.mmget_not_zero().ok_or(ESRCH)?);
|
| 441 | {
|
| 442 | let vma_read;
|
| 443 | let mmap_read;
|
| 444 | let vma = if let Some(ret) = mm.lock_vma_under_rcu(vma_addr) {
|
| 445 | vma_read = ret;
|
| 446 | check_vma(&vma_read, self)
|
| 447 | } else {
|
| 448 | mmap_read = mm.mmap_read_lock();
|
| 449 | mmap_read
|
| 450 | .vma_lookup(vma_addr)
|
| 451 | .and_then(|vma| check_vma(vma, self))
|
| 452 | };
|
| 453 |
|
| 454 | match vma {
|
| 455 | Some(vma) => vma.vm_insert_page(user_page_addr, &new_page)?,
|
| 456 | None => return Err(ESRCH),
|
| 457 | }
|
| 458 | }
|
| 459 |
|
| 460 | let inner = self.lock.lock();
|
| 461 |
|
| 462 | |
| 463 | |
| 464 | |
| 465 | |
| 466 | |
| 467 | |
| 468 | unsafe { PageInfo::set_page(page_info, new_page) };
|
| 469 |
|
| 470 | drop(inner);
|
| 471 | drop(mm_mutex);
|
| 472 |
|
| 473 | Ok(())
|
| 474 | }
|
| 475 |
|
| 476 | |
| 477 | |
| 478 | |
| 479 | pub(crate) fn stop_using_range(&self, start: usize, end: usize) {
|
| 480 | if start >= end {
|
| 481 | return;
|
| 482 | }
|
| 483 | let inner = self.lock.lock();
|
| 484 | assert!(end <= inner.size);
|
| 485 |
|
| 486 | for i in (start..end).rev() {
|
| 487 | |
| 488 | let page_info = unsafe { inner.pages.add(i) };
|
| 489 |
|
| 490 | |
| 491 | if let Some(page) = unsafe { PageInfo::get_page(page_info) } {
|
| 492 | |
| 493 | unsafe { PageInfo::list_lru_add(page_info, page.nid(), self.shrinker) };
|
| 494 | }
|
| 495 | }
|
| 496 | }
|
| 497 |
|
| 498 | |
| 499 | |
| 500 | |
| 501 | |
| 502 | |
| 503 | unsafe fn iterate<T>(&self, mut offset: usize, mut size: usize, mut cb: T) -> Result
|
| 504 | where
|
| 505 | T: FnMut(&Page, usize, usize) -> Result,
|
| 506 | {
|
| 507 | if size == 0 {
|
| 508 | return Ok(());
|
| 509 | }
|
| 510 |
|
| 511 | let (pages, num_pages) = {
|
| 512 | let inner = self.lock.lock();
|
| 513 | (inner.pages, inner.size)
|
| 514 | };
|
| 515 | let num_bytes = num_pages << PAGE_SHIFT;
|
| 516 |
|
| 517 | |
| 518 | if offset.checked_add(size).ok_or(EFAULT)? > num_bytes {
|
| 519 | return Err(EFAULT);
|
| 520 | }
|
| 521 |
|
| 522 | let mut page_index = offset >> PAGE_SHIFT;
|
| 523 | offset &= PAGE_SIZE - 1;
|
| 524 | while size > 0 {
|
| 525 | let available = usize::min(size, PAGE_SIZE - offset);
|
| 526 | |
| 527 | let page_info = unsafe { pages.add(page_index) };
|
| 528 | |
| 529 | |
| 530 | let page = unsafe { PageInfo::get_page(page_info) };
|
| 531 | if page.is_none() {
|
| 532 | pr_warn!("Page is null!");
|
| 533 | }
|
| 534 | let page = page.ok_or(EFAULT)?;
|
| 535 | cb(page, offset, available)?;
|
| 536 | size -= available;
|
| 537 | page_index += 1;
|
| 538 | offset = 0;
|
| 539 | }
|
| 540 | Ok(())
|
| 541 | }
|
| 542 |
|
| 543 | |
| 544 | |
| 545 | |
| 546 | |
| 547 | |
| 548 | pub(crate) unsafe fn copy_from_user_slice(
|
| 549 | &self,
|
| 550 | reader: &mut UserSliceReader,
|
| 551 | offset: usize,
|
| 552 | size: usize,
|
| 553 | ) -> Result {
|
| 554 | |
| 555 | unsafe {
|
| 556 | self.iterate(offset, size, |page, offset, to_copy| {
|
| 557 | page.copy_from_user_slice_raw(reader, offset, to_copy)
|
| 558 | })
|
| 559 | }
|
| 560 | }
|
| 561 |
|
| 562 | |
| 563 | |
| 564 | |
| 565 | |
| 566 | |
| 567 | pub(crate) unsafe fn read<T: FromBytes>(&self, offset: usize) -> Result<T> {
|
| 568 | let mut out = MaybeUninit::<T>::uninit();
|
| 569 | let mut out_offset = 0;
|
| 570 | |
| 571 | unsafe {
|
| 572 | self.iterate(offset, size_of::<T>(), |page, offset, to_copy| {
|
| 573 | |
| 574 | let obj_ptr = out.as_mut_ptr().cast::<u8>().add(out_offset);
|
| 575 | |
| 576 | page.read_raw(obj_ptr, offset, to_copy)?;
|
| 577 | out_offset += to_copy;
|
| 578 | Ok(())
|
| 579 | })?;
|
| 580 | }
|
| 581 | |
| 582 | Ok(unsafe { out.assume_init() })
|
| 583 | }
|
| 584 |
|
| 585 | |
| 586 | |
| 587 | |
| 588 | |
| 589 | |
| 590 | pub(crate) unsafe fn write<T: ?Sized>(&self, offset: usize, obj: &T) -> Result {
|
| 591 | let mut obj_offset = 0;
|
| 592 | |
| 593 | unsafe {
|
| 594 | self.iterate(offset, size_of_val(obj), |page, offset, to_copy| {
|
| 595 | |
| 596 | let obj_ptr = ptr::from_ref(obj).cast::<u8>().add(obj_offset);
|
| 597 | |
| 598 | page.write_raw(obj_ptr, offset, to_copy)?;
|
| 599 | obj_offset += to_copy;
|
| 600 | Ok(())
|
| 601 | })
|
| 602 | }
|
| 603 | }
|
| 604 |
|
| 605 | |
| 606 | |
| 607 | |
| 608 | |
| 609 | |
| 610 | pub(crate) unsafe fn fill_zero(&self, offset: usize, size: usize) -> Result {
|
| 611 | |
| 612 | unsafe {
|
| 613 | self.iterate(offset, size, |page, offset, len| {
|
| 614 | page.fill_zero_raw(offset, len)
|
| 615 | })
|
| 616 | }
|
| 617 | }
|
| 618 | }
|
| 619 |
|
| 620 | #[pinned_drop]
|
| 621 | impl PinnedDrop for ShrinkablePageRange {
|
| 622 | fn drop(self: Pin<&mut Self>) {
|
| 623 | let (pages, size) = {
|
| 624 | let lock = self.lock.lock();
|
| 625 | (lock.pages, lock.size)
|
| 626 | };
|
| 627 |
|
| 628 | if size == 0 {
|
| 629 | return;
|
| 630 | }
|
| 631 |
|
| 632 | |
| 633 | let mm_lock = self.mm_lock.lock();
|
| 634 |
|
| 635 | |
| 636 | |
| 637 | |
| 638 | |
| 639 | for i in 0..size {
|
| 640 | |
| 641 | let p_ptr = unsafe { pages.add(i) };
|
| 642 | |
| 643 | if let Some(p) = unsafe { PageInfo::get_page(p_ptr) } {
|
| 644 | |
| 645 | unsafe { PageInfo::list_lru_del(p_ptr, p.nid(), self.shrinker) };
|
| 646 | }
|
| 647 | }
|
| 648 |
|
| 649 | drop(mm_lock);
|
| 650 |
|
| 651 | |
| 652 | |
| 653 | |
| 654 | drop(unsafe { KVVec::from_raw_parts(pages, size, size) });
|
| 655 | }
|
| 656 | }
|
| 657 |
|
| 658 | |
| 659 | |
| 660 | #[no_mangle]
|
| 661 | unsafe extern "C" fn rust_shrink_count(
|
| 662 | shrink: *mut bindings::shrinker,
|
| 663 | _sc: *mut bindings::shrink_control,
|
| 664 | ) -> c_ulong {
|
| 665 | |
| 666 | let list_lru = unsafe { (*shrink).private_data.cast::<bindings::list_lru>() };
|
| 667 | |
| 668 | unsafe { bindings::list_lru_count(list_lru) }
|
| 669 | }
|
| 670 |
|
| 671 | |
| 672 | |
| 673 | #[no_mangle]
|
| 674 | unsafe extern "C" fn rust_shrink_scan(
|
| 675 | shrink: *mut bindings::shrinker,
|
| 676 | sc: *mut bindings::shrink_control,
|
| 677 | ) -> c_ulong {
|
| 678 | |
| 679 | let list_lru = unsafe { (*shrink).private_data.cast::<bindings::list_lru>() };
|
| 680 | |
| 681 | let nr_to_scan = unsafe { (*sc).nr_to_scan };
|
| 682 | |
| 683 | unsafe {
|
| 684 | bindings::list_lru_walk(
|
| 685 | list_lru,
|
| 686 | Some(rust_shrink_free_page),
|
| 687 | ptr::null_mut(),
|
| 688 | nr_to_scan,
|
| 689 | )
|
| 690 | }
|
| 691 | }
|
| 692 |
|
| 693 | const LRU_SKIP: bindings::lru_status = bindings::lru_status::LRU_SKIP;
|
| 694 | const LRU_REMOVED_ENTRY: bindings::lru_status = bindings::lru_status::LRU_REMOVED_RETRY;
|
| 695 |
|
| 696 | |
| 697 | |
| 698 | #[no_mangle]
|
| 699 | unsafe extern "C" fn rust_shrink_free_page(
|
| 700 | item: *mut bindings::list_head,
|
| 701 | lru: *mut bindings::list_lru_one,
|
| 702 | _cb_arg: *mut c_void,
|
| 703 | ) -> bindings::lru_status {
|
| 704 | |
| 705 | let page;
|
| 706 | let page_index;
|
| 707 | let mm;
|
| 708 | let vma_read;
|
| 709 | let mm_mutex;
|
| 710 | let vma_addr;
|
| 711 | let range_ptr;
|
| 712 |
|
| 713 | {
|
| 714 | |
| 715 | let info = item.cast::<PageInfo>();
|
| 716 | |
| 717 | range_ptr = unsafe { (*info).range };
|
| 718 | |
| 719 | let range = unsafe { &*range_ptr };
|
| 720 |
|
| 721 | mm = match range.mm.mmget_not_zero() {
|
| 722 | Some(mm) => MmWithUser::into_mmput_async(mm),
|
| 723 | None => return LRU_SKIP,
|
| 724 | };
|
| 725 |
|
| 726 | mm_mutex = match range.stable_trylock_mm() {
|
| 727 | Some(guard) => guard,
|
| 728 | None => return LRU_SKIP,
|
| 729 | };
|
| 730 |
|
| 731 | |
| 732 | let inner = match range.lock.try_lock() {
|
| 733 | Some(inner) => inner,
|
| 734 | None => return LRU_SKIP,
|
| 735 | };
|
| 736 |
|
| 737 | vma_addr = inner.vma_addr;
|
| 738 | vma_read = match mm.lock_vma_under_rcu(vma_addr) {
|
| 739 | Some(guard) => guard,
|
| 740 | None => return LRU_SKIP,
|
| 741 | };
|
| 742 |
|
| 743 | |
| 744 | unsafe { bindings::list_lru_isolate(lru, item) };
|
| 745 |
|
| 746 | |
| 747 | page_index = unsafe { info.offset_from(inner.pages) } as usize;
|
| 748 |
|
| 749 | |
| 750 | |
| 751 | |
| 752 | |
| 753 | |
| 754 | page = unsafe { PageInfo::take_page(info) };
|
| 755 |
|
| 756 | |
| 757 | |
| 758 | |
| 759 | }
|
| 760 |
|
| 761 | |
| 762 | unsafe { bindings::spin_unlock(&raw mut (*lru).lock) };
|
| 763 |
|
| 764 | if let Some(vma) = check_vma(&vma_read, range_ptr) {
|
| 765 | let user_page_addr = vma_addr + (page_index << PAGE_SHIFT);
|
| 766 | vma.zap_vma_range(user_page_addr, PAGE_SIZE);
|
| 767 | }
|
| 768 |
|
| 769 | drop(vma_read);
|
| 770 | drop(mm_mutex);
|
| 771 | drop(mm);
|
| 772 | drop(page);
|
| 773 |
|
| 774 | LRU_REMOVED_ENTRY
|
| 775 | }
|