* Search for the given physical page "m" in the free lists. If the search * succeeds, remove "m" from the free lists and return TRUE. Otherwise, return * FALSE, indicating that "m" is not in the free lists. * * The free page queues must be locked. */
| 1293 | * The free page queues must be locked. |
| 1294 | */ |
| 1295 | boolean_t |
| 1296 | vm_phys_unfree_page(vm_page_t m) |
| 1297 | { |
| 1298 | struct vm_freelist *fl; |
| 1299 | struct vm_phys_seg *seg; |
| 1300 | vm_paddr_t pa, pa_half; |
| 1301 | vm_page_t m_set, m_tmp; |
| 1302 | int order; |
| 1303 | |
| 1304 | /* |
| 1305 | * First, find the contiguous, power of two-sized set of free |
| 1306 | * physical pages containing the given physical page "m" and |
| 1307 | * assign it to "m_set". |
| 1308 | */ |
| 1309 | seg = &vm_phys_segs[m->segind]; |
| 1310 | vm_domain_free_assert_locked(VM_DOMAIN(seg->domain)); |
| 1311 | for (m_set = m, order = 0; m_set->order == VM_NFREEORDER && |
| 1312 | order < VM_NFREEORDER - 1; ) { |
| 1313 | order++; |
| 1314 | pa = m->phys_addr & (~(vm_paddr_t)0 << (PAGE_SHIFT + order)); |
| 1315 | if (pa >= seg->start) |
| 1316 | m_set = &seg->first_page[atop(pa - seg->start)]; |
| 1317 | else |
| 1318 | return (FALSE); |
| 1319 | } |
| 1320 | if (m_set->order < order) |
| 1321 | return (FALSE); |
| 1322 | if (m_set->order == VM_NFREEORDER) |
| 1323 | return (FALSE); |
| 1324 | KASSERT(m_set->order < VM_NFREEORDER, |
| 1325 | ("vm_phys_unfree_page: page %p has unexpected order %d", |
| 1326 | m_set, m_set->order)); |
| 1327 | |
| 1328 | /* |
| 1329 | * Next, remove "m_set" from the free lists. Finally, extract |
| 1330 | * "m" from "m_set" using an iterative algorithm: While "m_set" |
| 1331 | * is larger than a page, shrink "m_set" by returning the half |
| 1332 | * of "m_set" that does not contain "m" to the free lists. |
| 1333 | */ |
| 1334 | fl = (*seg->free_queues)[m_set->pool]; |
| 1335 | order = m_set->order; |
| 1336 | vm_freelist_rem(fl, m_set, order); |
| 1337 | while (order > 0) { |
| 1338 | order--; |
| 1339 | pa_half = m_set->phys_addr ^ (1 << (PAGE_SHIFT + order)); |
| 1340 | if (m->phys_addr < pa_half) |
| 1341 | m_tmp = &seg->first_page[atop(pa_half - seg->start)]; |
| 1342 | else { |
| 1343 | m_tmp = m_set; |
| 1344 | m_set = &seg->first_page[atop(pa_half - seg->start)]; |
| 1345 | } |
| 1346 | vm_freelist_add(fl, m_tmp, order, 0); |
| 1347 | } |
| 1348 | KASSERT(m_set == m, ("vm_phys_unfree_page: fatal inconsistency")); |
| 1349 | return (TRUE); |
| 1350 | } |
| 1351 | |
| 1352 | /* |
no test coverage detected