This diff primarily impacts reservations and paging. I took the opportunity to do some light refactoring for consistency. I made the vm_domain more of a first class structure and renamed a couple of functions and added many new ones to indicate that they operate on properties of the domain. I made some variable names more consistent across files where I was already making changes. I tried to make the API around domains more coherent since I expect it to become more stable. I use the integer 'domain' when crossing module boundaries so that we don't need to pollute more code with vm structures and 'struct vm_domain *vmd' in functions associated with paging.
The paging changes remove all counters except for wire_count from vmmeter. The paging targets and control variables are all properties of the domain. They are summed for presentation to the user. The atomics on global queue counts are now gone. There are global bitmasks of low and severe domains that are used as allocation hints in a few places. VM_WAIT() calls wait for !low now. The only VM_WAIT calls that remain are fault, pte allocation, and some drm code which I believe could be modified to use WAITFAIL. Everything else sleeps on a specific domain now.
I did make laundry per-domain. I realize this may be somewhat controversial although i did discuss with Mark first. My opinion is that we already have multiple I/O threads and we're likely to also have multiple I/O devices on machines with many domains. The code is structurally much simpler using multiple laundry threads in any event. So I chose to go this way.
There are a few cases where code really wants to know a global free count. This is done by looping over all domains and summing. With only three exceptions, swap, and tmpfs, I removed this potentially expensive loop from performance sensitive code. ZFS uses it but I believe only in irregularly called functions.
The reservation changes are as previously discussed. I added some more comments to detail the locking. I resolved the unlocked rv access Mark pointed out. Briefly, this protected the reservation structures with the free lock from the domain they belong to. The object's rvq is protected with a reservation object lock array. This also keeps the object/pindex stable in a reservation which is on the rvq so either this or the free lock may be used to inspect those members.
There are a few places where we have to iterate and swap free locks when pages are not all from the same domain. This really suggests that we should look at the round-robin code and give it a stride so non-reservation allocations don't switch domains for every page. I will continue to refine this in future patches.
I have early perf results from mjg_ that show double the pagefault performance on a microbenchmark and 1/3rd less system time on a 4 socket buildkernel. I am just now starting to benchmark myself.