2013-12-17 19:27:08 +04:00
|
|
|
#include <sys/uio.h>
|
2013-12-17 19:27:09 +04:00
|
|
|
#include <fcntl.h>
|
|
|
|
#include <linux/falloc.h>
|
2013-12-17 19:27:07 +04:00
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include "crtools.h"
|
2013-12-17 19:27:08 +04:00
|
|
|
#include "page-read.h"
|
|
|
|
#include "restorer.h"
|
|
|
|
|
2013-12-18 14:57:17 +04:00
|
|
|
static int cr_dedup_one_pagemap(int pid);
|
2013-12-17 19:27:07 +04:00
|
|
|
|
|
|
|
int cr_dedup(void)
|
|
|
|
{
|
2013-12-17 19:27:08 +04:00
|
|
|
int close_ret, ret = 0;
|
|
|
|
int pid;
|
|
|
|
DIR * dirp;
|
|
|
|
struct dirent *ent;
|
|
|
|
|
|
|
|
dirp = opendir(CR_PARENT_LINK);
|
|
|
|
if (dirp == NULL) {
|
|
|
|
pr_perror("Can't enter previous snapshot folder, error=%d", errno);
|
|
|
|
ret = -1;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
errno = 0;
|
|
|
|
ent = readdir(dirp);
|
|
|
|
if (ent == NULL) {
|
|
|
|
if (errno) {
|
|
|
|
pr_perror("Failed readdir, error=%d", errno);
|
|
|
|
ret = -1;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = sscanf(ent->d_name, "pagemap-%d.img", &pid);
|
|
|
|
if (ret == 1) {
|
|
|
|
pr_info("pid=%d\n", pid);
|
|
|
|
ret = cr_dedup_one_pagemap(pid);
|
|
|
|
if (ret < 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
err:
|
|
|
|
if (dirp) {
|
|
|
|
close_ret = closedir(dirp);
|
|
|
|
if (close_ret == -1)
|
|
|
|
return close_ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
pr_info("Deduplicated\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-12-18 14:57:17 +04:00
|
|
|
static int cr_dedup_one_pagemap(int pid)
|
2013-12-17 19:27:08 +04:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
struct page_read pr;
|
|
|
|
struct page_read * prp;
|
|
|
|
struct iovec iov;
|
|
|
|
|
2014-02-28 15:19:19 +04:00
|
|
|
ret = open_page_read(pid, &pr, O_RDWR);
|
2013-12-17 19:27:08 +04:00
|
|
|
if (ret) {
|
|
|
|
ret = -1;
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
prp = pr.parent;
|
|
|
|
if (!prp)
|
|
|
|
goto exit;
|
|
|
|
|
|
|
|
ret = pr.get_pagemap(&pr, &iov);
|
|
|
|
if (ret <= 0)
|
|
|
|
goto exit;
|
|
|
|
|
|
|
|
while (1) {
|
2013-12-26 11:10:00 +04:00
|
|
|
pr_debug("dedup iovec base=%lu, len=%zu\n", (unsigned long)iov.iov_base, iov.iov_len);
|
2013-12-17 19:27:08 +04:00
|
|
|
if (!pr.pe->in_parent) {
|
|
|
|
ret = dedup_one_iovec(prp, &iov);
|
|
|
|
if (ret)
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
pr.put_pagemap(&pr);
|
|
|
|
ret = pr.get_pagemap(&pr, &iov);
|
|
|
|
if (ret <= 0)
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
exit:
|
|
|
|
pr.close(&pr);
|
|
|
|
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-02-19 18:56:30 +04:00
|
|
|
int punch_hole(int fd, unsigned long off, unsigned long len)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
pr_debug("Punch!/%lu/%lu/\n", off, len);
|
|
|
|
ret = fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
|
|
|
|
off, len);
|
|
|
|
if (ret != 0) {
|
|
|
|
pr_perror("Error punching hole");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-12-17 19:27:08 +04:00
|
|
|
int dedup_one_iovec(struct page_read *pr, struct iovec *iov)
|
|
|
|
{
|
|
|
|
unsigned long off;
|
2013-12-17 19:27:09 +04:00
|
|
|
unsigned long off_real;
|
2013-12-17 19:27:08 +04:00
|
|
|
unsigned long iov_end;
|
|
|
|
|
|
|
|
iov_end = (unsigned long)iov->iov_base + iov->iov_len;
|
|
|
|
off = (unsigned long)iov->iov_base;
|
|
|
|
while (1) {
|
|
|
|
int ret;
|
|
|
|
struct iovec piov;
|
2014-02-05 10:44:00 +04:00
|
|
|
unsigned long piov_end;
|
2014-01-20 17:21:56 +04:00
|
|
|
struct iovec tiov;
|
|
|
|
struct page_read * prp;
|
|
|
|
|
2013-12-17 19:27:08 +04:00
|
|
|
ret = seek_pagemap_page(pr, off, false);
|
2014-01-24 15:50:24 +04:00
|
|
|
if (ret == -1)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (ret == 0) {
|
|
|
|
if (off < pr->cvaddr && pr->cvaddr < iov_end)
|
|
|
|
off = pr->cvaddr;
|
|
|
|
else
|
|
|
|
return 0;
|
2013-12-17 19:27:08 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!pr->pe)
|
|
|
|
return -1;
|
|
|
|
pagemap2iovec(pr->pe, &piov);
|
|
|
|
piov_end = (unsigned long)piov.iov_base + piov.iov_len;
|
2013-12-17 19:27:09 +04:00
|
|
|
off_real = lseek(pr->fd_pg, 0, SEEK_CUR);
|
|
|
|
if (!pr->pe->in_parent) {
|
2014-02-19 18:56:30 +04:00
|
|
|
ret = punch_hole(pr->fd_pg, off_real, min(piov_end, iov_end) - off);
|
|
|
|
if (ret == -1)
|
|
|
|
return ret;
|
2013-12-17 19:27:09 +04:00
|
|
|
}
|
2014-02-19 18:56:30 +04:00
|
|
|
|
2014-01-20 17:21:56 +04:00
|
|
|
prp = pr->parent;
|
|
|
|
if (prp) {
|
|
|
|
/* recursively */
|
2014-02-05 10:44:00 +04:00
|
|
|
pr_debug("Go to next parent level\n");
|
2014-01-20 17:21:56 +04:00
|
|
|
tiov.iov_base = (void*)off;
|
|
|
|
tiov.iov_len = min(piov_end, iov_end) - off;
|
|
|
|
ret = dedup_one_iovec(prp, &tiov);
|
|
|
|
if (ret != 0)
|
|
|
|
return -1;
|
|
|
|
}
|
2013-12-17 19:27:08 +04:00
|
|
|
|
|
|
|
if (piov_end < iov_end) {
|
|
|
|
off = piov_end;
|
|
|
|
continue;
|
|
|
|
} else
|
|
|
|
return 0;
|
|
|
|
}
|
2013-12-17 19:27:07 +04:00
|
|
|
return 0;
|
|
|
|
}
|