xref: /haiku/src/add-ons/kernel/drivers/disk/virtual/ram_disk/cache_support.h (revision dcbba214309ee718136c47adcd5096b858d685d7)
1 /*
2  * Copyright 2010-2013, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Copyright 2024, Haiku, Inc. All rights reserved.
4  * Distributed under the terms of the MIT license.
5  */
6 #ifndef CACHE_SUPPORT_H
7 #define CACHE_SUPPORT_H
8 
9 
10 static void
cache_get_pages(VMCache * cache,off_t offset,off_t length,bool isWrite,vm_page ** pages)11 cache_get_pages(VMCache* cache, off_t offset, off_t length, bool isWrite, vm_page** pages)
12 {
13 	// get the pages, we already have
14 	AutoLocker<VMCache> locker(cache);
15 
16 	size_t pageCount = length / B_PAGE_SIZE;
17 	size_t index = 0;
18 	size_t missingPages = 0;
19 
20 	while (length > 0) {
21 		vm_page* page = cache->LookupPage(offset);
22 		if (page != NULL) {
23 			if (page->busy) {
24 				cache->WaitForPageEvents(page, PAGE_EVENT_NOT_BUSY, true);
25 				continue;
26 			}
27 
28 			page->busy = true;
29 		} else
30 			missingPages++;
31 
32 		pages[index++] = page;
33 		offset += B_PAGE_SIZE;
34 		length -= B_PAGE_SIZE;
35 	}
36 
37 	locker.Unlock();
38 
39 	// For a write we need to reserve the missing pages.
40 	if (isWrite && missingPages > 0) {
41 		vm_page_reservation reservation;
42 		vm_page_reserve_pages(&reservation, missingPages,
43 			VM_PRIORITY_SYSTEM);
44 
45 		for (size_t i = 0; i < pageCount; i++) {
46 			if (pages[i] != NULL)
47 				continue;
48 
49 			pages[i] = vm_page_allocate_page(&reservation, VM_PAGE_ALLOC_CLEAR
50 				| PAGE_STATE_WIRED | VM_PAGE_ALLOC_BUSY);
51 
52 			if (--missingPages == 0)
53 				break;
54 		}
55 
56 		vm_page_unreserve_pages(&reservation);
57 	}
58 }
59 
60 
61 static void
cache_put_pages(VMCache * cache,off_t offset,off_t length,vm_page ** pages,bool success)62 cache_put_pages(VMCache* cache, off_t offset, off_t length, vm_page** pages, bool success)
63 {
64 	AutoLocker<VMCache> locker(cache);
65 
66 	// Mark all pages unbusy. On error free the newly allocated pages.
67 	size_t index = 0;
68 
69 	while (length > 0) {
70 		vm_page* page = pages[index++];
71 		if (page != NULL) {
72 			if (page->CacheRef() == NULL) {
73 				if (success) {
74 					cache->InsertPage(page, offset);
75 					cache->MarkPageUnbusy(page);
76 					DEBUG_PAGE_ACCESS_END(page);
77 				} else
78 					vm_page_free(NULL, page);
79 			} else {
80 				cache->MarkPageUnbusy(page);
81 			}
82 		}
83 
84 		offset += B_PAGE_SIZE;
85 		length -= B_PAGE_SIZE;
86 	}
87 }
88 
89 
90 #endif	// CACHE_SUPPORT_H
91