[Devel] [PATCH RHEL9 COMMIT] dm-tracking: Track request after it completed

Konstantin Khorenko khorenko at virtuozzo.com
Wed Oct 27 19:13:53 MSK 2021


The commit is pushed to "branch-rh9-5.14.vz9.1.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh9-5.14.0-4.vz9.10.20
------>
commit ae2c1ce302a46aad93caae509ee7e84df03af043
Author: Kirill Tkhai <ktkhai at virtuozzo.com>
Date:   Wed Oct 27 19:13:53 2021 +0300

    dm-tracking: Track request after it completed
    
    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 <ktkhai at 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,


More information about the Devel mailing list