static int dump_one_shmem(struct shmem_info_dump *si) { struct iovec *iovs; struct page_pipe *pp; struct page_xfer xfer; int err, ret = -1, fd; unsigned char *map = NULL; void *addr = NULL; unsigned long pfn, nrpages; pr_info("Dumping shared memory %ld\n", si->shmid); nrpages = (si->size + PAGE_SIZE - 1) / PAGE_SIZE; map = xmalloc(nrpages * sizeof(*map)); if (!map) goto err; fd = open_proc(si->pid, "map_files/%lx-%lx", si->start, si->end); if (fd < 0) goto err; addr = mmap(NULL, si->size, PROT_READ, MAP_SHARED, fd, 0); close(fd); if (addr == MAP_FAILED) { pr_err("Can't map shmem 0x%lx (0x%lx-0x%lx)\n", si->shmid, si->start, si->end); goto err; } /* * We can't use pagemap here, because this vma is * not mapped to us at all, but mincore reports the * pagecache status of a file, which is correct in * this case. */ err = mincore(addr, si->size, map); if (err) goto err_unmap; iovs = xmalloc(((nrpages + 1) / 2) * sizeof(struct iovec)); if (!iovs) goto err_unmap; pp = create_page_pipe((nrpages + 1) / 2, iovs, true); if (!pp) goto err_iovs; err = open_page_xfer(&xfer, CR_FD_SHMEM_PAGEMAP, si->shmid); if (err) goto err_pp; for (pfn = 0; pfn < nrpages; pfn++) { if (!(map[pfn] & PAGE_RSS)) continue; again: ret = page_pipe_add_page(pp, (unsigned long)addr + pfn * PAGE_SIZE); if (ret == -EAGAIN) { ret = dump_pages(pp, &xfer, addr); if (ret) goto err_xfer; page_pipe_reinit(pp); goto again; } else if (ret) goto err_xfer; } ret = dump_pages(pp, &xfer, addr); err_xfer: xfer.close(&xfer); err_pp: destroy_page_pipe(pp); err_iovs: xfree(iovs); err_unmap: munmap(addr, si->size); err: xfree(map); return ret; }
static int dump_one_shmem(struct shmem_info_dump *si) { struct iovec *iovs; struct page_pipe *pp; struct page_pipe_buf *ppb; struct page_xfer xfer; int err, ret = -1, fd; unsigned char *map = NULL; void *addr = NULL; unsigned long pfn, nrpages; pr_info("Dumping shared memory %ld\n", si->shmid); nrpages = (si->size + PAGE_SIZE - 1) / PAGE_SIZE; map = xmalloc(nrpages * sizeof(*map)); if (!map) goto err; fd = open_proc(si->pid, "map_files/%lx-%lx", si->start, si->end); if (fd < 0) goto err; addr = mmap(NULL, si->size, PROT_READ, MAP_SHARED, fd, 0); close(fd); if (addr == MAP_FAILED) { pr_err("Can't map shmem 0x%lx (0x%lx-0x%lx)\n", si->shmid, si->start, si->end); goto err; } /* * We can't use pagemap here, because this vma is * not mapped to us at all, but mincore reports the * pagecache status of a file, which is correct in * this case. */ err = mincore(addr, si->size, map); if (err) goto err_unmap; iovs = xmalloc(((nrpages + 1) / 2) * sizeof(struct iovec)); if (!iovs) goto err_unmap; pp = create_page_pipe((nrpages + 1) / 2, iovs); if (!pp) goto err_iovs; for (pfn = 0; pfn < nrpages; pfn++) { if (!(map[pfn] & PAGE_RSS)) continue; if (page_pipe_add_page(pp, (unsigned long)addr + pfn * PAGE_SIZE)) goto err_pp; } list_for_each_entry(ppb, &pp->bufs, l) if (vmsplice(ppb->p[1], ppb->iov, ppb->nr_segs, SPLICE_F_GIFT | SPLICE_F_NONBLOCK) != ppb->pages_in * PAGE_SIZE) { pr_perror("Can't get shmem into page-pipe"); goto err_pp; } err = open_page_xfer(&xfer, CR_FD_SHMEM_PAGEMAP, si->shmid); if (err) goto err_pp; ret = page_xfer_dump_pages(&xfer, pp, (unsigned long)addr); xfer.close(&xfer); err_pp: destroy_page_pipe(pp); err_iovs: xfree(iovs); err_unmap: munmap(addr, si->size); err: xfree(map); return ret; }