Commit 1821aced authored by Andrei Vagin's avatar Andrei Vagin Committed by Pavel Emelyanov

shmem: use lseek(SEEK_DATA) instead of mincore

When pages are swapped out we can't detect their presence
with mincore.

Pavel found that lseek(SEEK_DATA, SEEK_HOLE) can show which
pages are used.

travis-ci: success for shmem: use lseek(SEEK_DATA) instead of mincore
Cc: Eugene Batalov <eabatalov89@gmail.com>
Cc: Cyrill Gorcunov <gorcunov@openvz.org>
Signed-off-by: 's avatarAndrei Vagin <avagin@virtuozzo.com>
Looks-good-to: Eugene Batalov <eabatalov89@gmail.com>
Signed-off-by: 's avatarPavel Emelyanov <xemul@virtuozzo.com>
parent 606d88f9
...@@ -24,6 +24,11 @@ ...@@ -24,6 +24,11 @@
#include "protobuf.h" #include "protobuf.h"
#include "images/pagemap.pb-c.h" #include "images/pagemap.pb-c.h"
#ifndef SEEK_DATA
#define SEEK_DATA 3
#define SEEK_HOLE 4
#endif
/* /*
* Hash table and routines for keeping shmid -> shmem_xinfo mappings * Hash table and routines for keeping shmid -> shmem_xinfo mappings
*/ */
...@@ -629,14 +634,40 @@ static int dump_pages(struct page_pipe *pp, struct page_xfer *xfer, void *addr) ...@@ -629,14 +634,40 @@ static int dump_pages(struct page_pipe *pp, struct page_xfer *xfer, void *addr)
return page_xfer_dump_pages(xfer, pp, (unsigned long)addr); return page_xfer_dump_pages(xfer, pp, (unsigned long)addr);
} }
static int next_data_segment(int fd, unsigned long pfn,
unsigned long *next_data_pfn, unsigned long *next_hole_pfn)
{
off_t off;
off = lseek(fd, pfn * PAGE_SIZE, SEEK_DATA);
if (off == (off_t) -1) {
if (errno == ENXIO) {
*next_data_pfn = ~0UL;
*next_hole_pfn = ~0UL;
return 0;
}
pr_perror("Unable to lseek(SEEK_DATA)");
return -1;
}
*next_data_pfn = off / PAGE_SIZE;
off = lseek(fd, off, SEEK_HOLE);
if (off == (off_t) -1) {
pr_perror("Unable to lseek(SEEK_HOLE)");
return -1;
}
*next_hole_pfn = off / PAGE_SIZE;
return 0;
}
static int dump_one_shmem(struct shmem_info *si) static int dump_one_shmem(struct shmem_info *si)
{ {
struct page_pipe *pp; struct page_pipe *pp;
struct page_xfer xfer; struct page_xfer xfer;
int err, ret = -1, fd; int err, ret = -1, fd;
unsigned char *mc_map = NULL;
void *addr = NULL; void *addr = NULL;
unsigned long pfn, nrpages; unsigned long pfn, nrpages, next_data_pnf = 0, next_hole_pfn = 0;
pr_info("Dumping shared memory %ld\n", si->shmid); pr_info("Dumping shared memory %ld\n", si->shmid);
...@@ -645,7 +676,6 @@ static int dump_one_shmem(struct shmem_info *si) ...@@ -645,7 +676,6 @@ static int dump_one_shmem(struct shmem_info *si)
goto err; goto err;
addr = mmap(NULL, si->size, PROT_READ, MAP_SHARED, fd, 0); addr = mmap(NULL, si->size, PROT_READ, MAP_SHARED, fd, 0);
close(fd);
if (addr == MAP_FAILED) { if (addr == MAP_FAILED) {
pr_err("Can't map shmem 0x%lx (0x%lx-0x%lx)\n", pr_err("Can't map shmem 0x%lx (0x%lx-0x%lx)\n",
si->shmid, si->start, si->end); si->shmid, si->start, si->end);
...@@ -653,13 +683,6 @@ static int dump_one_shmem(struct shmem_info *si) ...@@ -653,13 +683,6 @@ static int dump_one_shmem(struct shmem_info *si)
} }
nrpages = (si->size + PAGE_SIZE - 1) / PAGE_SIZE; nrpages = (si->size + PAGE_SIZE - 1) / PAGE_SIZE;
mc_map = xmalloc(nrpages * sizeof(*mc_map));
if (!mc_map)
goto err_unmap;
/* We can't rely only on PME bits for anon shmem */
err = mincore(addr, si->size, mc_map);
if (err)
goto err_unmap;
pp = create_page_pipe((nrpages + 1) / 2, NULL, PP_CHUNK_MODE); pp = create_page_pipe((nrpages + 1) / 2, NULL, PP_CHUNK_MODE);
if (!pp) if (!pp)
...@@ -674,13 +697,21 @@ static int dump_one_shmem(struct shmem_info *si) ...@@ -674,13 +697,21 @@ static int dump_one_shmem(struct shmem_info *si)
bool use_mc = true; bool use_mc = true;
unsigned long pgaddr; unsigned long pgaddr;
if (pfn >= next_hole_pfn &&
next_data_segment(fd, pfn, &next_data_pnf, &next_hole_pfn))
goto err_xfer;
if (is_shmem_tracking_en()) { if (is_shmem_tracking_en()) {
pgstate = get_pstate(si->pstate_map, pfn); pgstate = get_pstate(si->pstate_map, pfn);
use_mc = pgstate == PST_DONT_DUMP; use_mc = pgstate == PST_DONT_DUMP;
} }
if (use_mc && !(mc_map[pfn] & PAGE_RSS)) if (use_mc) {
continue; if (pfn < next_data_pnf)
pgstate = PST_ZERO;
else
pgstate = PST_DIRTY;
}
pgaddr = (unsigned long)addr + pfn * PAGE_SIZE; pgaddr = (unsigned long)addr + pfn * PAGE_SIZE;
again: again:
...@@ -708,7 +739,7 @@ err_pp: ...@@ -708,7 +739,7 @@ err_pp:
err_unmap: err_unmap:
munmap(addr, si->size); munmap(addr, si->size);
err: err:
xfree(mc_map); close_safe(&fd);
return ret; return ret;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment