Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I allocate memory buffers which may be reclaimed by the OS for caching in a Mac OS X kernel extension?

Based on documentation and xnu source I've read, I understand that Mac OS X caches file I/O using the Unified Buffer Cache (UBC). The UBC grows as big as it can based on available RAM, but UBC pages are some of the first to be sacrificed when memory gets tighter.

In my driver, I deal with various on-disk metadata. I'd like to be able to use the UBC or a similar mechanism to keep MRU caches of this data around to speed things up, yet give the kernel the ability to take back that memory whenever it needs to. The metadata however doesn't represent file data, and thus doesn't fall directly into the UBC's domain. Is there a lower-level mechanism I can use, or can I somehow use only the part of the UBC that deals with the buffers themselves?

I'm currently hunting around the HFS+ source code to try and figure out whether and how it caches filesystem metadata, albeit without much success.

The main alternative is of course to reserve a specific memory region for caches and do my own LRU culling. I can choose a fixed cache size or use some kind of heuristic, but it's always going to use too little memory when RAM is abundant and too much when it isn't.

Update:

After searching some more, I've found that instances of IOBufferMemoryDescriptor may be created with the kIOMemoryPurgeable option. This lets you call IOMemoryDescriptor::setPurgeable() on it to mark the memory "fair game" for discarding. I'll try it and update the question with results.

like image 314
pmdj Avatar asked Oct 24 '22 21:10

pmdj


1 Answers

You are correct. Set kIOMemoryPurgeable as one of the options when you request the memory. It starts off as nonvolatile, and may be paged out, but won't be discarded.

When you want to let the OS discard it, call setPurgeable(kIOMemoryPurgeableVolatile, &oldState ); and the OS will discard it if necessary, rather than paging it to disk.

When you want to access the memory, you must call setPurgeable(kIOMemoryPurgeableKeepCurrent, &oldState ); and check if(oldState != kIOMemoryPurgeableEmpty) which will be true if the memory is still available, and false if it has been discarded.

I would be interested to hear if you ran into any catches.

like image 175
Adam Davis Avatar answered Oct 31 '22 09:10

Adam Davis