Now, before stopping push_backup, userspace backup tool can ask ploop
about blocks needed to backup, but not reported as backed up:

        ctl->direction = PLOOP_PEEK;
        ctl->n_extents = n; /* where n >= 1*/
        ret = ioctl(pfd, PLOOP_IOC_PUSH_BACKUP_IO, ctl);

If push_backup was really done completely (i.e. all blocks in main bitmask
were reported as backed up), ret will be zero, and ctl->n_extents too.

Overwise, if some blocks were missed to backup, the ioctl will fill
ctl->extents[] with info about such "missed" blocks.

https://jira.sw.ru/browse/PSBM-47764

Signed-off-by: Maxim Patlasov <mpatla...@virtuozzo.com>
---
 drivers/block/ploop/dev.c         |   47 +++++++++++++++++----
 drivers/block/ploop/push_backup.c |   84 +++++++++++++++++++++++++++++++++++++
 drivers/block/ploop/push_backup.h |    2 +
 include/linux/ploop/ploop_if.h    |    1 
 4 files changed, 125 insertions(+), 9 deletions(-)

diff --git a/drivers/block/ploop/dev.c b/drivers/block/ploop/dev.c
index 27827a8..db55be3 100644
--- a/drivers/block/ploop/dev.c
+++ b/drivers/block/ploop/dev.c
@@ -4643,24 +4643,27 @@ pb_init_done:
        return rc;
 }
 
-static int ploop_push_backup_io_read(struct ploop_device *plo, unsigned long 
arg,
-                                    struct ploop_push_backup_io_ctl *ctl)
+static int ploop_push_backup_io_get(struct ploop_device *plo,
+               unsigned long arg, struct ploop_push_backup_io_ctl *ctl,
+               int (*get)(struct ploop_pushbackup_desc *, cluster_t *,
+                          cluster_t *, unsigned))
 {
        struct ploop_push_backup_ctl_extent *e;
        unsigned n_extents = 0;
        int rc = 0;
+       cluster_t clu = 0;
+       cluster_t len = 0;
 
        e = kmalloc(sizeof(*e) * ctl->n_extents, GFP_KERNEL);
        if (!e)
                return -ENOMEM;
 
        while (n_extents < ctl->n_extents) {
-               cluster_t clu, len;
-               rc = ploop_pb_get_pending(plo->pbd, &clu, &len, n_extents);
+               rc = get(plo->pbd, &clu, &len, n_extents);
                if (rc == -ENOENT && n_extents)
                        break;
                else if (rc)
-                       goto io_read_done;
+                       goto io_get_done;
 
                e[n_extents].clu = clu;
                e[n_extents].len = len;
@@ -4670,18 +4673,44 @@ static int ploop_push_backup_io_read(struct 
ploop_device *plo, unsigned long arg
        rc = -EFAULT;
        ctl->n_extents = n_extents;
        if (copy_to_user((void*)arg, ctl, sizeof(*ctl)))
-               goto io_read_done;
+               goto io_get_done;
        if (n_extents &&
            copy_to_user((void*)(arg + sizeof(*ctl)), e,
                         n_extents * sizeof(*e)))
-                       goto io_read_done;
+                       goto io_get_done;
        rc = 0;
 
-io_read_done:
+io_get_done:
        kfree(e);
        return rc;
 }
 
+static int ploop_push_backup_io_read(struct ploop_device *plo,
+               unsigned long arg, struct ploop_push_backup_io_ctl *ctl)
+{
+       return ploop_push_backup_io_get(plo, arg, ctl, ploop_pb_get_pending);
+}
+
+static int ploop_push_backup_io_peek(struct ploop_device *plo,
+               unsigned long arg, struct ploop_push_backup_io_ctl *ctl)
+{
+       int rc;
+
+       ploop_quiesce(plo);
+       rc = ploop_push_backup_io_get(plo, arg, ctl, ploop_pb_peek);
+       ploop_relax(plo);
+
+       if (rc == -ENOENT) {
+               ctl->n_extents = 0;
+               if (copy_to_user((void*)arg, ctl, sizeof(*ctl)))
+                       rc = -EFAULT;
+               else
+                       rc = 0;
+       }
+
+       return rc;
+}
+
 static int ploop_push_backup_io_write(struct ploop_device *plo, unsigned long 
arg,
                                      struct ploop_push_backup_io_ctl *ctl)
 {
@@ -4737,6 +4766,8 @@ static int ploop_push_backup_io(struct ploop_device *plo, 
unsigned long arg)
                return ploop_push_backup_io_read(plo, arg, &ctl);
        case PLOOP_WRITE:
                return ploop_push_backup_io_write(plo, arg, &ctl);
+       case PLOOP_PEEK:
+               return ploop_push_backup_io_peek(plo, arg, &ctl);
        }
 
        return -EINVAL;
diff --git a/drivers/block/ploop/push_backup.c 
b/drivers/block/ploop/push_backup.c
index 376052d..e8fa88d 100644
--- a/drivers/block/ploop/push_backup.c
+++ b/drivers/block/ploop/push_backup.c
@@ -303,9 +303,17 @@ int ploop_pb_init(struct ploop_pushbackup_desc *pbd, __u8 
*uuid, bool full)
        memcpy(pbd->cbt_uuid, uuid, sizeof(pbd->cbt_uuid));
 
        if (full) {
-               int i;
+               int i, off;
                for (i = 0; i < NR_PAGES(pbd->ppb_block_max); i++)
                        memset(page_address(pbd->ppb_map[i]), 0xff, PAGE_SIZE);
+
+               /* nullify bits beyond [0, pbd->ppb_block_max) range */
+               off = pbd->ppb_block_max & (BITS_PER_PAGE -1);
+               i = pbd->ppb_block_max >> (PAGE_SHIFT + 3);
+               while (off && off < BITS_PER_PAGE) {
+                       __clear_bit(off, page_address(pbd->ppb_map[i]));
+                       off++;
+               }
                return 0;
        }
 
@@ -638,6 +646,80 @@ get_pending_unlock:
        return err;
 }
 
+static void fill_page_to_backup(struct ploop_pushbackup_desc *pbd,
+                               unsigned long idx, struct page *page)
+{
+       u32 *dst = page_address(page);
+       u32 *fin = page_address(page) + PAGE_SIZE;
+       u32 *map = page_address(pbd->ppb_map[idx]);
+       u32 *rep = page_address(pbd->reported_map[idx]);
+
+       while (dst < fin) {
+               *dst = *map & ~*rep;
+               dst++;
+               map++;
+               rep++;
+       }
+}
+
+int ploop_pb_peek(struct ploop_pushbackup_desc *pbd,
+                 cluster_t *clu_p, cluster_t *len_p, unsigned n_done)
+{
+       unsigned long block = *clu_p + *len_p;
+       unsigned long idx = block >> (PAGE_SHIFT + 3);
+       unsigned long clu = 0;
+       unsigned long len = 0;
+       unsigned long off, off2;
+       struct page *page;
+       bool found = 0;
+
+       if (block >= pbd->ppb_block_max)
+               return -ENOENT;
+
+       page = alloc_page(GFP_KERNEL);
+       if (!page)
+               return -ENOMEM;
+
+       spin_lock(&pbd->ppb_lock);
+       while (block < pbd->ppb_block_max) {
+               fill_page_to_backup(pbd, idx, page);
+               off = block & (BITS_PER_PAGE -1);
+
+               if (!found) {
+                       clu = find_next_bit(page_address(page),
+                                              BITS_PER_PAGE, off);
+                       if (clu == BITS_PER_PAGE)
+                               goto next;
+
+                       off = clu;
+                       clu += idx << (PAGE_SHIFT + 3);
+                       found = 1;
+               }
+
+               if (found) {
+                       off2 = find_next_zero_bit(page_address(page),
+                                                 BITS_PER_PAGE, off);
+                       len += off2 - off;
+                       if (off2 != BITS_PER_PAGE)
+                               break;
+               }
+
+       next:
+               idx++;
+               block = idx << (PAGE_SHIFT + 3);
+       }
+       spin_unlock(&pbd->ppb_lock);
+
+       __free_page(page);
+
+       if (!found)
+               return -ENOENT;
+
+       *clu_p = clu;
+       *len_p = len;
+       return 0;
+}
+
 static void ploop_pb_process_extent(struct rb_root *tree, cluster_t clu,
                                    cluster_t len, struct list_head *ready_list,
                                    int *n_found)
diff --git a/drivers/block/ploop/push_backup.h 
b/drivers/block/ploop/push_backup.h
index 1644785..da1563d 100644
--- a/drivers/block/ploop/push_backup.h
+++ b/drivers/block/ploop/push_backup.h
@@ -10,6 +10,8 @@ int ploop_pb_get_uuid(struct ploop_pushbackup_desc *pbd, __u8 
*uuid);
 
 int ploop_pb_get_pending(struct ploop_pushbackup_desc *pbd,
                         cluster_t *clu_p, cluster_t *len_p, unsigned n_done);
+int ploop_pb_peek(struct ploop_pushbackup_desc *pbd,
+                 cluster_t *clu_p, cluster_t *len_p, unsigned n_done);
 void ploop_pb_put_reported(struct ploop_pushbackup_desc *pbd,
                           cluster_t clu, cluster_t len);
 
diff --git a/include/linux/ploop/ploop_if.h b/include/linux/ploop/ploop_if.h
index 81cc8d1..0c2b69d 100644
--- a/include/linux/ploop/ploop_if.h
+++ b/include/linux/ploop/ploop_if.h
@@ -202,6 +202,7 @@ struct ploop_push_backup_ctl_extent
 enum {
        PLOOP_READ = 0, /* wait for requests */
        PLOOP_WRITE,    /* ACK requests */
+       PLOOP_PEEK,     /* peek at what to be backed up */
 };
 
 struct ploop_push_backup_io_ctl

_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to