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