Otherwise there is a race in case of userspace calls
"tracking_get_next" and dumps cluster before the request
is written completely.

Signed-off-by: Kirill Tkhai <ktk...@virtuozzo.com>
---
 drivers/md/dm-tracking.c |   47 +++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 40 insertions(+), 7 deletions(-)

diff --git a/drivers/md/dm-tracking.c b/drivers/md/dm-tracking.c
index d723596fee44..a8880a83d270 100644
--- a/drivers/md/dm-tracking.c
+++ b/drivers/md/dm-tracking.c
@@ -34,18 +34,23 @@ struct dm_tracking {
        struct mutex ctl_mutex;
 };
 
+struct treq {
+       sector_t pos;
+       u32 bytes;
+};
+
 static sector_t get_dev_size(struct dm_dev *dev)
 {
        return i_size_read(dev->bdev->bd_inode) >> SECTOR_SHIFT;
 }
 
-static void track_rq_clus(struct dm_tracking *dmt, struct request *rq)
+static void track_rq_clus(struct dm_tracking *dmt, struct treq *treq)
 {
-       loff_t off = to_bytes(blk_rq_pos(rq));
+       loff_t off = to_bytes(treq->pos);
        u64 start_clu, end_clu, clu;
 
        start_clu = off / dmt->clu_size;
-       end_clu = (off + blk_rq_bytes(rq) - 1) / dmt->clu_size;
+       end_clu = (off + treq->bytes - 1) / dmt->clu_size;
 
        for (clu = start_clu; clu <= end_clu; clu++) {
                set_bit(clu, dmt->bitmap);
@@ -61,20 +66,25 @@ static int dmt_clone_and_map(struct dm_target *ti, struct 
request *rq,
 {
        struct dm_tracking *dmt = ti->private;
        struct block_device *bdev = dmt->origin_dev->bdev;
+       struct treq *treq = NULL;
        struct request_queue *q;
        struct request *clone;
 
+       map_context->ptr = NULL;
        if (blk_rq_bytes(rq) && op_is_write(req_op(rq))) {
-               spin_lock_irq(&dmt->lock);
-               if (dmt->bitmap)
-                       track_rq_clus(dmt, rq);
-               spin_unlock_irq(&dmt->lock);
+               treq = kmalloc(sizeof(*treq), GFP_ATOMIC);
+               if (!treq)
+                       return DM_MAPIO_REQUEUE;
+               treq->pos = blk_rq_pos(rq);
+               treq->bytes = blk_rq_bytes(rq);
+               map_context->ptr = treq;
        }
 
        q = bdev_get_queue(bdev);
        clone = blk_get_request(q, rq->cmd_flags | REQ_NOMERGE,
                                BLK_MQ_REQ_NOWAIT);
        if (IS_ERR(clone)) {
+               kfree(treq);
                /* EBUSY, ENODEV or EWOULDBLOCK: requeue */
                if (blk_queue_dying(q))
                        return DM_MAPIO_DELAY_REQUEUE;
@@ -91,9 +101,31 @@ static int dmt_clone_and_map(struct dm_target *ti, struct 
request *rq,
 static void dmt_release_clone(struct request *clone,
                              union map_info *map_context)
 {
+       if (unlikely(map_context)) {
+               struct treq *treq = map_context->ptr;
+               kfree(treq);
+       }
+
        blk_put_request(clone);
 }
 
+static int dmt_end_io(struct dm_target *ti, struct request *clone,
+                     blk_status_t error, union map_info *map_context)
+{
+       struct treq *treq = map_context->ptr;
+       struct dm_tracking *dmt = ti->private;
+
+       if (treq) {
+               spin_lock_irq(&dmt->lock);
+               if (dmt->bitmap)
+                       track_rq_clus(dmt, treq);
+               spin_unlock_irq(&dmt->lock);
+               kfree(treq);
+       }
+
+       return DM_ENDIO_DONE;
+}
+
 static void dmt_destroy(struct dm_tracking *dmt)
 {
        if (dmt->origin_dev)
@@ -320,6 +352,7 @@ static struct target_type dmt_target = {
        .dtr = dmt_dtr,
        .clone_and_map_rq = dmt_clone_and_map,
        .release_clone_rq = dmt_release_clone,
+       .rq_end_io = dmt_end_io,
        .message = dmt_message,
        .iterate_devices = dmt_iterate_devices,
        .status = dmt_status,


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

Reply via email to