Hello,
I have been trying to implement a pager in L4Re where the pager employs a memory region of limited size to satisfy map requests for a dataspace occupying a larger virtual memory region. Upon receiving a map request, the pager identifies the dimensions of the flexpage to be sent to the task experiencing the page fault, and it populates the flexpage's memory with the appropriate data.
What this accomplishes so far is that when page faults occur in a task accessing the dataspace, mappings from virtual memory addresses are established in the task referring to the memory region populated by the pager. The task can read from page to page and keep getting new data.
However, as each new map request comes in, I want to be able to invalidate the mappings previously made by the pager. Otherwise, I get many pages in the task's address space referring to the same memory, which is obviously not what I intend.
Is it possible to send a flexpage from the pager in such a way that the mappings previously established by Fiasco.OC for the memory region are invalidated? Or have I missed some other mechanism for achieving what I am attempting? The L4Re documentation isn't helping me so much here, and I can't seem to find examples of this kind of thing in the source distribution.
Thanks for any help anyone can give!
Paul
Hi Paul,
AFAIK, you cannot unmap a page during a page fault reply. However, your pager can track the pages you mapped and call task->unmap() explicitly.
E.g. // assuming pagee_task of type L4::CapL4::Task pagee_task->unmap( l4_fpage(addr_of_prev_page, L4_PAGESIZE, L4_FPAGE_RWX), L4_FP_ALL_SPACES);
Note, that unmap operations are expensive, especially on multicore CPUs. To reduce the overhead you can call unmap_batch and provide an array of flex-pages. E.g. if you have a set of five pages to map, you can call unmap_batch on the first four pages when mapping the fifth.
Cheers, Philipp
On 3/17/19 4:44 PM, Paul Boddie wrote:
Hello,
I have been trying to implement a pager in L4Re where the pager employs a memory region of limited size to satisfy map requests for a dataspace occupying a larger virtual memory region. Upon receiving a map request, the pager identifies the dimensions of the flexpage to be sent to the task experiencing the page fault, and it populates the flexpage's memory with the appropriate data.
What this accomplishes so far is that when page faults occur in a task accessing the dataspace, mappings from virtual memory addresses are established in the task referring to the memory region populated by the pager. The task can read from page to page and keep getting new data.
However, as each new map request comes in, I want to be able to invalidate the mappings previously made by the pager. Otherwise, I get many pages in the task's address space referring to the same memory, which is obviously not what I intend.
Is it possible to send a flexpage from the pager in such a way that the mappings previously established by Fiasco.OC for the memory region are invalidated? Or have I missed some other mechanism for achieving what I am attempting? The L4Re documentation isn't helping me so much here, and I can't seem to find examples of this kind of thing in the source distribution.
Thanks for any help anyone can give!
Paul
l4-hackers mailing list l4-hackers@os.inf.tu-dresden.de http://os.inf.tu-dresden.de/mailman/listinfo/l4-hackers
On Monday 18. March 2019 08.35.56 Philipp Eppelt wrote:
AFAIK, you cannot unmap a page during a page fault reply.
I had looked into this and couldn't see a way of returning items that would provide the necessary information for unmapping previously mapped pages. I imagine that one could specify a flexpage with an appropriate base address and size, but then it isn't clear how its invalidation would be communicated.
I looked at the kernel code somewhat to see how it processes map items, but it also wasn't clear how such items might be able to cause unmapping.
However, your pager can track the pages you mapped and call task->unmap() explicitly.
E.g. // assuming pagee_task of type L4::CapL4::Task pagee_task->unmap( l4_fpage(addr_of_prev_page, L4_PAGESIZE, L4_FPAGE_RWX), L4_FP_ALL_SPACES);
I guess that the pager needs to know the identity of the task for which it is performing paging. As far as I understand it, this information isn't automatically available via the normal IPC interactions because it would expose the sender to potentially undesirable operations (such as the one being described) purely because it communicated with another task.
So, I imagine that the task must first provide its identity to the pager before paging begins. Then, any unmapping can take place as necessary.
Note, that unmap operations are expensive, especially on multicore CPUs. To reduce the overhead you can call unmap_batch and provide an array of flex-pages. E.g. if you have a set of five pages to map, you can call unmap_batch on the first four pages when mapping the fifth.
Thanks for the advice, Philipp! I did wonder whether this problem might have been solved within L4Re already but found nothing obvious (to me), and yet I would have thought that multiplexing access to a larger resource via a fixed set of pages would have been a familiar scenario.
Paul
On 3/18/19 11:31 AM, Paul Boddie wrote:
On Monday 18. March 2019 08.35.56 Philipp Eppelt wrote:
AFAIK, you cannot unmap a page during a page fault reply.
I had looked into this and couldn't see a way of returning items that would provide the necessary information for unmapping previously mapped pages. I imagine that one could specify a flexpage with an appropriate base address and size, but then it isn't clear how its invalidation would be communicated.
I looked at the kernel code somewhat to see how it processes map items, but it also wasn't clear how such items might be able to cause unmapping.
However, your pager can track the pages you mapped and call task->unmap() explicitly.
E.g. // assuming pagee_task of type L4::CapL4::Task pagee_task->unmap( l4_fpage(addr_of_prev_page, L4_PAGESIZE, L4_FPAGE_RWX), L4_FP_ALL_SPACES);
I guess that the pager needs to know the identity of the task for which it is performing paging. As far as I understand it, this information isn't automatically available via the normal IPC interactions because it would expose the sender to potentially undesirable operations (such as the one being described) purely because it communicated with another task.
So, I imagine that the task must first provide its identity to the pager before paging begins. Then, any unmapping can take place as necessary.
Actually, there is a unmap flag which allows you to unmap all child mappings of a memory fpage. So assume you have three address spaces, A, B, and C, and A maps a page FP to B as FP' and B maps FP' to C as FP".
So if B decides to call unmap on its own mapping FP' with L4_FP_OTHER_SPACES [0], it will just unmap FP" in C's address space. If A decides to call `L4Re::Env::env()->task()->unmap(FP, L4_FP_OTHER_SPACES)` it will unmap FP' in B and FP" in C.
I suppose that's the way for your pager to eliminate the mapping in its pagee.
To put it into code: L4Re::Env::env()->task()->unmap( l4_fpage(addr_in_this_task, L4_PAGESIZE, L4_FPAGE_RWX), L4_FP_OTHER_SPACES);
Cheers, Philipp
[0] http://l4re.org/doc/group__l4__task__api.html#ga3c24e67b976870a3e911c43c8338...
On Monday 18. March 2019 13.38.36 Philipp Eppelt wrote:
Actually, there is a unmap flag which allows you to unmap all child mappings of a memory fpage. So assume you have three address spaces, A, B, and C, and A maps a page FP to B as FP' and B maps FP' to C as FP".
So if B decides to call unmap on its own mapping FP' with L4_FP_OTHER_SPACES [0], it will just unmap FP" in C's address space. If A decides to call `L4Re::Env::env()->task()->unmap(FP, L4_FP_OTHER_SPACES)` it will unmap FP' in B and FP" in C.
This seems to be exactly what I am looking for. I want the pager to hold on to its own mapping whilst invalidating the mapping given to its client.
I suppose that's the way for your pager to eliminate the mapping in its pagee.
To put it into code: L4Re::Env::env()->task()->unmap( l4_fpage(addr_in_this_task, L4_PAGESIZE, L4_FPAGE_RWX), L4_FP_OTHER_SPACES);
Or as I did it:
l4_task_unmap(L4RE_THIS_TASK_CAP, _fpage, L4_FP_OTHER_SPACES);
Where _fpage is the previously-issued flexpage. After this, the new flexpage item is sent as a response to the map request.
And this works just as I had hoped: as the task traverses the pages in the dataspace, it causes page faults regardless of whether it has seen those pages before.
Many thanks for showing me the appropriate mechanism!
Paul
[0] http://l4re.org/doc/group__l4__task__api.html#ga3c24e67b976870a3e911c43c8338 2f66
On Monday 18. March 2019 17.09.02 Paul Boddie wrote:
Many thanks for showing me the appropriate mechanism!
And in case anyone casually reading the list is interested, I wrote up some of my experiences investigating dataspaces and related concepts in L4Re:
http://blogs.fsfe.org/pboddie/?p=2469
There are probably some inaccuracies in there, but perhaps it is still useful to others in a similar situation.
Paul
l4-hackers@os.inf.tu-dresden.de