dm: fix mempool NULL pointer race when completing IO
[sfrench/cifs-2.6.git] / drivers / md / dm.c
index a011d09cb0faca9f2acd6b1c3208169724ae3f73..76d9da49fda7563bf45a834243c46f4c691104af 100644 (file)
@@ -496,18 +496,17 @@ static void start_io_acct(struct dm_io *io)
                                    false, 0, &io->stats_aux);
 }
 
-static void end_io_acct(struct dm_io *io)
+static void end_io_acct(struct mapped_device *md, struct bio *bio,
+                       unsigned long start_time, struct dm_stats_aux *stats_aux)
 {
-       struct mapped_device *md = io->md;
-       struct bio *bio = io->orig_bio;
-       unsigned long duration = jiffies - io->start_time;
+       unsigned long duration = jiffies - start_time;
 
-       bio_end_io_acct(bio, io->start_time);
+       bio_end_io_acct(bio, start_time);
 
        if (unlikely(dm_stats_used(&md->stats)))
                dm_stats_account_io(&md->stats, bio_data_dir(bio),
                                    bio->bi_iter.bi_sector, bio_sectors(bio),
-                                   true, duration, &io->stats_aux);
+                                   true, duration, stats_aux);
 
        /* nudge anyone waiting on suspend queue */
        if (unlikely(wq_has_sleeper(&md->wait)))
@@ -790,6 +789,8 @@ void dm_io_dec_pending(struct dm_io *io, blk_status_t error)
        blk_status_t io_error;
        struct bio *bio;
        struct mapped_device *md = io->md;
+       unsigned long start_time = 0;
+       struct dm_stats_aux stats_aux;
 
        /* Push-back supersedes any I/O errors */
        if (unlikely(error)) {
@@ -821,8 +822,10 @@ void dm_io_dec_pending(struct dm_io *io, blk_status_t error)
                }
 
                io_error = io->status;
-               end_io_acct(io);
+               start_time = io->start_time;
+               stats_aux = io->stats_aux;
                free_io(md, io);
+               end_io_acct(md, bio, start_time, &stats_aux);
 
                if (io_error == BLK_STS_DM_REQUEUE)
                        return;