[Devel] [PATCH RH9 1/2] dm-tracking: Track request after it completed
Kirill Tkhai
ktkhai at virtuozzo.com
Wed Oct 27 18:08:44 MSK 2021
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