Store cbts in a list instead of a single pointer.
Update all APIs to work with user-specified bitmap.

https://virtuozzo.atlassian.net/browse/VSTOR-96269
Signed-off-by: Andrey Zhadchenko <andrey.zhadche...@virtuozzo.com>
---
 block/blk-cbt.c         | 174 +++++++++++++++++++++-------------------
 block/blk-core.c        |   2 +
 include/linux/blkdev.h  |   2 +-
 include/uapi/linux/fs.h |   2 +-
 4 files changed, 96 insertions(+), 84 deletions(-)

diff --git a/block/blk-cbt.c b/block/blk-cbt.c
index 8ae993143098..8b0d07ee757c 100644
--- a/block/blk-cbt.c
+++ b/block/blk-cbt.c
@@ -53,6 +53,7 @@ struct cbt_info {
        blkcnt_t snp_block_max;
 
        spinlock_t lock;
+       struct list_head list;
 };
 
 
@@ -112,7 +113,11 @@ static int cbt_page_alloc(struct cbt_info  **cbt_pp, 
unsigned long idx,
        if (likely(!test_bit(CBT_DEAD, &cbt->flags))) {
                cbt->count++;
        } else {
-               struct cbt_info *new = rcu_dereference(cbt->queue->cbt);
+               struct cbt_info *i, *new = NULL;
+
+               list_for_each_entry_rcu(i, &cbt->queue->cbt_list, list)
+                       if (!memcmp(i->name, cbt->name, sizeof(cbt->name)))
+                               new = i;
 
                spin_unlock_irq(&cbt->lock);
                /* was cbt updated ? */
@@ -216,33 +221,26 @@ static int __blk_cbt_set(struct cbt_info  *cbt, blkcnt_t 
block,
        return (pages_missed && *pages_missed) ? -EAGAIN : 0;
 }
 
-static void blk_cbt_add(struct request_queue *q, blkcnt_t start, blkcnt_t len)
+static void blk_cbt_add(struct cbt_info *cbt, blkcnt_t start, blkcnt_t len)
 {
-       struct cbt_info *cbt;
        struct cbt_extent *ex;
        struct cbt_extent old;
        blkcnt_t end;
-       /* Check per-cpu cache */
-
-       rcu_read_lock();
-       cbt = rcu_dereference(q->cbt);
-       if (unlikely(!cbt))
-               goto out_rcu;
 
        if (unlikely(test_bit(CBT_ERROR, &cbt->flags)))
-               goto out_rcu;
+               return;
        end = DIV_ROUND_UP(start + len, 1 << cbt->block_bits);
        start >>= cbt->block_bits;
        len = end - start;
        if (unlikely(test_bit(CBT_NOCACHE, &cbt->flags))) {
                __blk_cbt_set(cbt, start, len, 1, 1, NULL, NULL);
-               goto out_rcu;
+               return;
        }
        ex = get_cpu_ptr(cbt->cache);
        if (ex->start + ex->len == start) {
                ex->len += len;
                put_cpu_ptr(cbt->cache);
-               goto out_rcu;
+               return;
        }
        old = *ex;
        ex->start = start;
@@ -251,18 +249,23 @@ static void blk_cbt_add(struct request_queue *q, blkcnt_t 
start, blkcnt_t len)
 
        if (likely(old.len))
                __blk_cbt_set(cbt, old.start, old.len, 1, 1, NULL, NULL);
+}
+
+void blk_cbt_bio_queue(struct request_queue *q, struct bio *bio)
+{
+       struct cbt_info *cbt;
+
+       rcu_read_lock();
+       if (list_empty(&q->cbt_list) || bio_data_dir(bio) == READ || 
!bio->bi_iter.bi_size)
+               goto out_rcu;
+
+       list_for_each_entry_rcu(cbt, &q->cbt_list, list)
+               blk_cbt_add(cbt, bio->bi_iter.bi_sector << 9, 
bio->bi_iter.bi_size);
+
 out_rcu:
        rcu_read_unlock();
 }
 
-inline void blk_cbt_bio_queue(struct request_queue *q, struct bio *bio)
-{
-       if (!q->cbt || bio_data_dir(bio) == READ || !bio->bi_iter.bi_size)
-               return;
-
-       blk_cbt_add(q, bio->bi_iter.bi_sector << 9, bio->bi_iter.bi_size);
-}
-
 static struct cbt_info *do_cbt_alloc(struct request_queue *q, __u8 *name,
                                     loff_t size, loff_t blocksize)
 {
@@ -272,6 +275,7 @@ static struct cbt_info *do_cbt_alloc(struct request_queue 
*q, __u8 *name,
        if (!cbt)
                return ERR_PTR(-ENOMEM);
 
+       INIT_LIST_HEAD(&cbt->list);
        cbt->block_bits = ilog2(blocksize);
        cbt->block_max  = DIV_ROUND_UP(size, blocksize);
        spin_lock_init(&cbt->lock);
@@ -365,6 +369,17 @@ static int copy_cbt_to_user(struct page **map, unsigned 
long size,
         return 0;
 }
 
+static struct cbt_info *blk_cbt_find(struct request_queue *q, __u8 *name)
+{
+       struct cbt_info *cbt;
+
+       list_for_each_entry(cbt, &q->cbt_list, list)
+               if (!memcmp(name, cbt->name, CBT_NAME_LENGTH))
+                       return cbt;
+
+       return NULL;
+}
+
 static int blk_cbt_snap_create(struct request_queue *q, __u8 *name,
                               struct blk_user_cbt_snap_create __user *arg)
 {
@@ -382,8 +397,7 @@ static int blk_cbt_snap_create(struct request_queue *q, 
__u8 *name,
                return -EFAULT;
 
        mutex_lock(&cbt_mutex);
-       cbt = q->cbt;
-
+       cbt = blk_cbt_find(q, name);
        if (!cbt) {
                mutex_unlock(&cbt_mutex);
                return -ENOENT;
@@ -392,11 +406,6 @@ static int blk_cbt_snap_create(struct request_queue *q, 
__u8 *name,
        BUG_ON(!cbt->map);
        BUG_ON(!cbt->block_max);
 
-       if (!name || memcmp(name, cbt->name, sizeof(cbt->name))) {
-               mutex_unlock(&cbt_mutex);
-               return -EINVAL;
-       }
-
        if (cbt->snp_map) {
                mutex_unlock(&cbt_mutex);
                return -EBUSY;
@@ -461,7 +470,7 @@ static int blk_cbt_snap_drop(struct request_queue *q, __u8 
*name)
        int ret;
 
        mutex_lock(&cbt_mutex);
-       cbt = q->cbt;
+       cbt = blk_cbt_find(q, name);
 
        ret = -ENOENT;
        if (!cbt)
@@ -470,10 +479,6 @@ static int blk_cbt_snap_drop(struct request_queue *q, __u8 
*name)
        BUG_ON(!cbt->map);
        BUG_ON(!cbt->block_max);
 
-       ret = -EINVAL;
-       if (!name || memcmp(name, cbt->name, sizeof(cbt->name)))
-               goto out;
-
        ret = -ENODEV;
        map = cbt->snp_map;
        if (!map)
@@ -511,7 +516,7 @@ static int blk_cbt_snap_merge_back(struct request_queue *q, 
__u8 *name)
        int ret;
 
        mutex_lock(&cbt_mutex);
-       cbt = q->cbt;
+       cbt = blk_cbt_find(q, name);
 
        ret = -ENOENT;
        if (!cbt)
@@ -520,10 +525,6 @@ static int blk_cbt_snap_merge_back(struct request_queue 
*q, __u8 *name)
        BUG_ON(!cbt->map);
        BUG_ON(!cbt->block_max);
 
-       ret = -EINVAL;
-       if (!name || memcmp(name, cbt->name, sizeof(cbt->name)))
-               goto out;
-
        map = cbt->snp_map;
        block_max = cbt->snp_block_max;
        ret = -ENODEV;
@@ -568,33 +569,21 @@ static int blk_cbt_snap_merge_back(struct request_queue 
*q, __u8 *name)
        return ret;
 }
 
-void blk_cbt_update_size(struct block_device *bdev)
+static void blk_cbt_update_cbt_size(struct cbt_info *cbt, loff_t new_sz)
 {
-       struct request_queue *q;
-       struct cbt_info *new, *cbt;
+       struct cbt_info *new;
        unsigned long to_cpy, idx;
        unsigned bsz;
-       loff_t new_sz = i_size_read(bdev->bd_inode);
        int in_use = 0;
 
-       if (!bdev->bd_disk || !bdev_get_queue(bdev))
-               return;
-
-       q = bdev_get_queue(bdev);
-       mutex_lock(&cbt_mutex);
-       cbt = q->cbt;
-       if (!cbt) {
-               mutex_unlock(&cbt_mutex);
-               return;
-       }
        bsz = 1 << cbt->block_bits;
        if (DIV_ROUND_UP(new_sz, bsz) <= cbt->block_max)
-               goto err_mtx;
+               return;
 
-       new = do_cbt_alloc(q, cbt->name, new_sz, bsz);
+       new = do_cbt_alloc(cbt->queue, cbt->name, new_sz, bsz);
        if (IS_ERR(new)) {
                set_bit(CBT_ERROR, &cbt->flags);
-               goto err_mtx;
+               return;
        }
        to_cpy = NR_PAGES(cbt->block_max);
        set_bit(CBT_NOCACHE, &cbt->flags);
@@ -606,15 +595,27 @@ void blk_cbt_update_size(struct block_device *bdev)
                if (CBT_PAGE(new, idx))
                        get_page(CBT_PAGE(new, idx));
        }
-       rcu_assign_pointer(q->cbt, new);
+       list_replace_rcu(&cbt->list, &new->list);
        in_use = cbt->count;
        spin_unlock_irq(&cbt->lock);
        if (!in_use)
                call_rcu(&cbt->rcu, &cbt_release_callback);
-err_mtx:
+}
+
+void blk_cbt_update_size(struct block_device *bdev)
+{
+       struct request_queue *q;
+       struct cbt_info *cbt;
+
+       if (!bdev->bd_disk || !bdev_get_queue(bdev))
+               return;
+
+       q = bdev_get_queue(bdev);
+       mutex_lock(&cbt_mutex);
+       list_for_each_entry(cbt, &q->cbt_list, list)
+               blk_cbt_update_cbt_size(cbt, i_size_read(bdev->bd_inode));
+
        mutex_unlock(&cbt_mutex);
-
-
 }
 
 static int cbt_ioc_init(struct block_device *bdev, struct blk_user_cbt_info 
__user *ucbt_ioc)
@@ -632,16 +633,13 @@ static int cbt_ioc_init(struct block_device *bdev, struct 
blk_user_cbt_info __us
 
        q = bdev_get_queue(bdev);
        mutex_lock(&cbt_mutex);
-       if (q->cbt) {
-               ret = -EBUSY;
-               goto err_mtx;
-       }
+
        cbt = do_cbt_alloc(q, ci.ci_name, i_size_read(bdev->bd_inode), 
ci.ci_blksize);
        if (IS_ERR(cbt))
                ret = PTR_ERR(cbt);
        else
-               rcu_assign_pointer(q->cbt, cbt);
-err_mtx:
+               list_add_tail_rcu(&q->cbt_list, &cbt->list);
+
        mutex_unlock(&cbt_mutex);
        return ret;
 }
@@ -667,35 +665,46 @@ static void cbt_release_callback(struct rcu_head *head)
        kfree(cbt);
 }
 
-void blk_cbt_release(struct request_queue *q)
+static void blk_cbt_del(struct cbt_info *cbt)
 {
-       struct cbt_info *cbt;
-       int in_use = 0;
        unsigned long flags;
+       int in_use;
 
-       cbt = q->cbt;
-       if (!cbt)
-               return;
        spin_lock_irqsave(&cbt->lock, flags);
        set_bit(CBT_DEAD, &cbt->flags);
-       rcu_assign_pointer(q->cbt, NULL);
+       list_del_rcu(&cbt->list);
        in_use = cbt->count;
        spin_unlock_irqrestore(&cbt->lock, flags);
        if (!in_use)
                call_rcu(&cbt->rcu, &cbt_release_callback);
 }
 
-static int cbt_ioc_stop(struct block_device *bdev)
+void blk_cbt_release(struct request_queue *q)
 {
+       struct cbt_info *cbt, *tmp;
+
+       list_for_each_entry_safe(cbt, tmp, &q->cbt_list, list)
+               blk_cbt_del(cbt);
+}
+
+static int cbt_ioc_stop(struct block_device *bdev, struct blk_user_cbt_info 
__user *ucbt_ioc)
+{
+       struct blk_user_cbt_info ci;
        struct request_queue *q;
+       struct cbt_info *cbt;
+
+       if (copy_from_user(&ci, ucbt_ioc, sizeof(ci)))
+               return -EFAULT;
 
        mutex_lock(&cbt_mutex);
        q = bdev_get_queue(bdev);
-       if(!q->cbt) {
-               mutex_unlock(&cbt_mutex);
-               return -EINVAL;
-       }
-       blk_cbt_release(q);
+
+       cbt = blk_cbt_find(q, ci.ci_name);
+       if (!cbt)
+               return -ENOMEM;
+
+       blk_cbt_del(cbt);
+
        mutex_unlock(&cbt_mutex);
        return 0;
 }
@@ -839,7 +848,8 @@ static int cbt_ioc_get(struct block_device *bdev, struct 
blk_user_cbt_info __use
        ret = -EINVAL;
        q = bdev_get_queue(bdev);
        mutex_lock(&cbt_mutex);
-       cbt = q->cbt;
+
+       cbt = blk_cbt_find(q, ci.ci_name);
        if (!cbt ||
            (ci.ci_start >> cbt->block_bits) > cbt->block_max)
                goto ioc_get_failed;
@@ -925,7 +935,7 @@ static int cbt_ioc_set(struct block_device *bdev, struct 
blk_user_cbt_info __use
 
        ret = -EINVAL;
        mutex_lock(&cbt_mutex);
-       cbt = q->cbt;
+       cbt = blk_cbt_find(q, ci.ci_name);
        if (!cbt)
                goto ioc_set_failed;
 
@@ -948,8 +958,8 @@ static int cbt_ioc_set(struct block_device *bdev, struct 
blk_user_cbt_info __use
 
                ex.start  = cur_ex->ce_physical >> cbt->block_bits;
                ex.len  = DIV_ROUND_UP(cur_ex->ce_length, 1 << cbt->block_bits);
-               if (ex.start > q->cbt->block_max ||
-                   ex.start + ex.len > q->cbt->block_max ||
+               if (ex.start > cbt->block_max ||
+                   ex.start + ex.len > cbt->block_max ||
                    ex.len == 0) {
                        ret = -EINVAL;
                        break;
@@ -1007,7 +1017,7 @@ int blk_cbt_ioctl(struct block_device *bdev, unsigned 
cmd, char __user *arg)
        case BLKCBTSTART:
                return cbt_ioc_init(bdev, ucbt_ioc);
        case BLKCBTSTOP:
-               return cbt_ioc_stop(bdev);
+               return cbt_ioc_stop(bdev, ucbt_ioc);
        case BLKCBTSET:
                return cbt_ioc_set(bdev, ucbt_ioc, 1);
        case BLKCBTCLR:
diff --git a/block/blk-core.c b/block/blk-core.c
index 6abad29dd501..e3aa923f399e 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -428,6 +428,8 @@ struct request_queue *blk_alloc_queue(int node_id)
        init_waitqueue_head(&q->mq_freeze_wq);
        mutex_init(&q->mq_freeze_lock);
 
+       INIT_LIST_HEAD(&q->cbt_list);
+
        blkg_init_queue(q);
 
        /*
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index fcbc83909b91..3009964707e6 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -520,7 +520,7 @@ struct request_queue {
        struct throtl_data *td;
 #endif
 #ifdef CONFIG_BLK_DEV_CBT
-       struct cbt_info *cbt;
+       struct list_head cbt_list;
 #endif
        struct rcu_head         rcu_head;
        wait_queue_head_t       mq_freeze_wq;
diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h
index 47efa7ef05a0..667157fe864a 100644
--- a/include/uapi/linux/fs.h
+++ b/include/uapi/linux/fs.h
@@ -170,7 +170,7 @@ struct blk_user_cbt_snap_create {
 };
 
 #define BLKCBTSTART _IOR(0x12,200, struct blk_user_cbt_info)
-#define BLKCBTSTOP _IO(0x12,201)
+#define BLKCBTSTOP _IOR(0x12, 201, struct blk_user_cbt_info)
 #define BLKCBTGET _IOWR(0x12,202,struct blk_user_cbt_info)
 #define BLKCBTSET _IOR(0x12,203,struct blk_user_cbt_info)
 #define BLKCBTCLR _IOR(0x12,204,struct blk_user_cbt_info)
-- 
2.39.3

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

Reply via email to