[CRIU] [RFC PATCH 07/12] lazy-pages: add handling of UFFD_EVENT_REMAP
Mike Rapoport
rppt at linux.vnet.ibm.com
Tue Jan 10 06:20:43 PST 2017
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. 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 ;-)
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