[CRIU] [RFC PATCH 07/12] lazy-pages: add handling of UFFD_EVENT_REMAP
Pavel Emelyanov
xemul at virtuozzo.com
Tue Jan 10 08:15:28 PST 2017
On 01/10/2017 05:20 PM, Mike Rapoport wrote:
> On Tue, Jan 10, 2017 at 05:07:01PM +0300, Pavel Emelyanov wrote:
>> On 01/09/2017 11:23 AM, Mike Rapoport wrote:
>>> When the restored process calls mremap(), we will see #PF's on the new
>>> addresses and we have to create a correspondence between the addresses
>>> found in the dump and the actual addresses the process uses. If the
>>> mremap() call causes the mapping to grow, the additional part will receive
>>> zero pages, as expected.
>>>
>>> FIXME: is the mapping shrinks, we will try to fill the dropped part and
>>> lazy-pages daemon will fail. It should be possible to track VMA changes in
>>> the lazy-pages daemon, but simpler, and, apparently, more correct would be
>>> to add UFFD_EVENT_MUNMAP to the kernel.
>>>
>>> Signed-off-by: Mike Rapoport <rppt at linux.vnet.ibm.com>
>>> ---
>>> criu/uffd.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++-
>>> 1 file changed, 46 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/criu/uffd.c b/criu/uffd.c
>>> index 3bc7bc1..8bf4a14 100644
>>> --- a/criu/uffd.c
>>> +++ b/criu/uffd.c
>>> @@ -53,7 +53,12 @@ struct lazy_iovec {
>>> unsigned long len;
>>> };
>>>
>>> -struct lazy_pages_info;
>>> +struct lazy_remap {
>>> + struct list_head l;
>>> + unsigned long from;
>>> + unsigned long to;
>>> + unsigned long len;
>>> +};
>>>
>>> struct pf_info {
>>> unsigned long addr;
>>> @@ -65,6 +70,7 @@ struct lazy_pages_info {
>>>
>>> struct list_head iovs;
>>> struct list_head pfs;
>>> + struct list_head remaps;
>>>
>>> struct page_read pr;
>>>
>>> @@ -92,6 +98,7 @@ static struct lazy_pages_info *lpi_init(void)
>>> memset(lpi, 0, sizeof(*lpi));
>>> INIT_LIST_HEAD(&lpi->iovs);
>>> INIT_LIST_HEAD(&lpi->pfs);
>>> + INIT_LIST_HEAD(&lpi->remaps);
>>> INIT_LIST_HEAD(&lpi->l);
>>> lpi->lpfd.revent = handle_uffd_event;
>>>
>>> @@ -101,12 +108,15 @@ static struct lazy_pages_info *lpi_init(void)
>>> static void lpi_fini(struct lazy_pages_info *lpi)
>>> {
>>> struct lazy_iovec *p, *n;
>>> + struct lazy_remap *p1, *n1;
>>>
>>> if (!lpi)
>>> return;
>>> free(lpi->buf);
>>> list_for_each_entry_safe(p, n, &lpi->iovs, l)
>>> xfree(p);
>>> + list_for_each_entry_safe(p1, n1, &lpi->remaps, l)
>>> + xfree(p1);
>>> if (lpi->lpfd.fd > 0)
>>> close(lpi->lpfd.fd);
>>> if (lpi->pr.close)
>>> @@ -515,9 +525,17 @@ out:
>>> static int uffd_copy(struct lazy_pages_info *lpi, __u64 address, int nr_pages)
>>> {
>>> struct uffdio_copy uffdio_copy;
>>> + struct lazy_remap *r;
>>> unsigned long len = nr_pages * page_size();
>>> int rc;
>>>
>>> + list_for_each_entry(r, &lpi->remaps, l) {
>>> + if (address >= r->from && address < r->from + r->len) {
>>> + address += (r->to - r->from);
>>> + break;
>>> + }
>>> + }
>>> +
>>> uffdio_copy.dst = address;
>>> uffdio_copy.src = (unsigned long)lpi->buf;
>>> uffdio_copy.len = len;
>>> @@ -670,9 +688,27 @@ static int handle_madv_dontneed(struct lazy_pages_info *lpi,
>>> return 0;
>>> }
>>>
>>> +static int handle_remap(struct lazy_pages_info *lpi, struct uffd_msg *msg)
>>> +{
>>> + struct lazy_remap *remap;
>>> +
>>> + remap = xmalloc(sizeof(*remap));
>>> + if (!remap)
>>> + return -1;
>>> +
>>> + INIT_LIST_HEAD(&remap->l);
>>> + remap->from = msg->arg.remap.from;
>>> + remap->to = msg->arg.remap.to;
>>> + remap->len = msg->arg.remap.len;
>>> + list_add_tail(&remap->l, &lpi->remaps);
>>
>> Shouldn't we punch a hole in original region? Not to handle #PF there?
>
> I don't quite follow you here. The #PF's are delivered to uffd only if the
> VMA covering the range is registered with uffd. For moving remaps, the
> original address range will not be covered by a VMA with uffd.
Indeed :) Aren't you worried with the fact that the in-memory state of lazyd
will differ from the real state in the kernel?
> The only issue it the shrinking remaps (see changelog).
>
>> Also, what if one region is remapped somewhere, then remapped back? Will
>> we have two "patches" for it?
>> Also, what if we swap two regs with remap (a->c, b->a, c->b) what kind of
>> mess will we have here? %)
>
> You forgot a combination of fork() and mremap() events in arbitrary order ;-)
:D
> This makes the things even more funny.
>
> I can try to "remap" iovecs, but I remember that something bothered me when
> I first started doing it, just cannot remember what exactly...
:\
>>
>>> +
>>> + return 0;
>>> +}
>>> +
>>> static int handle_page_fault(struct lazy_pages_info *lpi, struct uffd_msg *msg)
>>> {
>>> struct pf_info *pf;
>>> + struct lazy_remap *r;
>>> __u64 address;
>>> int ret;
>>>
>>> @@ -695,6 +731,13 @@ static int handle_page_fault(struct lazy_pages_info *lpi, struct uffd_msg *msg)
>>> }
>>> #endif
>>>
>>> + list_for_each_entry(r, &lpi->remaps, l) {
>>> + if (address >= r->to && address < r->to + r->len) {
>>> + address -= (r->to - r->from);
>>> + break;
>>> + }
>>> + }
>>> +
>>> list_for_each_entry(pf, &lpi->pfs, l)
>>> if (pf->addr == address)
>>> return 0;
>>> @@ -742,6 +785,8 @@ static int handle_uffd_event(struct epoll_rfd *lpfd)
>>> return handle_page_fault(lpi, &msg);
>>> case UFFD_EVENT_MADVDONTNEED:
>>> return handle_madv_dontneed(lpi, &msg);
>>> + case UFFD_EVENT_REMAP:
>>> + return handle_remap(lpi, &msg);
>>> default:
>>> pr_err("unexpected uffd event %u\n", msg.event);
>>> return -1;
>>>
>>
>
> .
>
More information about the CRIU
mailing list