> 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
ACK
>
> 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