dm mpath: detect invalid map_context
Jun'ichi Nomura [Wed, 28 Mar 2012 17:41:25 +0000 (18:41 +0100)]
The map_context pointer should always be set. However, we have reports
that upon requeuing it is not set correctly.  So add set and clear
functions with a BUG_ON() to track the issue properly.

Signed-off-by: Jun'ichi Nomura <j-nomura@ce.jp.nec.com>
Cc: Mike Snitzer <snitzer@redhat.com>
Acked-by: Hannes Reinecke <hare@suse.de>
Tested-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Acked-by: Dave Wysochanski <dwysocha@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>

drivers/md/dm-mpath.c

index 801d92d..e92a000 100644 (file)
@@ -226,6 +226,27 @@ static void free_multipath(struct multipath *m)
        kfree(m);
 }
 
+static int set_mapinfo(struct multipath *m, union map_info *info)
+{
+       struct dm_mpath_io *mpio;
+
+       mpio = mempool_alloc(m->mpio_pool, GFP_ATOMIC);
+       if (!mpio)
+               return -ENOMEM;
+
+       memset(mpio, 0, sizeof(*mpio));
+       info->ptr = mpio;
+
+       return 0;
+}
+
+static void clear_mapinfo(struct multipath *m, union map_info *info)
+{
+       struct dm_mpath_io *mpio = info->ptr;
+
+       info->ptr = NULL;
+       mempool_free(mpio, m->mpio_pool);
+}
 
 /*-----------------------------------------------
  * Path selection
@@ -341,13 +362,14 @@ static int __must_push_back(struct multipath *m)
 }
 
 static int map_io(struct multipath *m, struct request *clone,
-                 struct dm_mpath_io *mpio, unsigned was_queued)
+                 union map_info *map_context, unsigned was_queued)
 {
        int r = DM_MAPIO_REMAPPED;
        size_t nr_bytes = blk_rq_bytes(clone);
        unsigned long flags;
        struct pgpath *pgpath;
        struct block_device *bdev;
+       struct dm_mpath_io *mpio = map_context->ptr;
 
        spin_lock_irqsave(&m->lock, flags);
 
@@ -423,7 +445,6 @@ static void dispatch_queued_ios(struct multipath *m)
 {
        int r;
        unsigned long flags;
-       struct dm_mpath_io *mpio;
        union map_info *info;
        struct request *clone, *n;
        LIST_HEAD(cl);
@@ -436,16 +457,15 @@ static void dispatch_queued_ios(struct multipath *m)
                list_del_init(&clone->queuelist);
 
                info = dm_get_rq_mapinfo(clone);
-               mpio = info->ptr;
 
-               r = map_io(m, clone, mpio, 1);
+               r = map_io(m, clone, info, 1);
                if (r < 0) {
-                       mempool_free(mpio, m->mpio_pool);
+                       clear_mapinfo(m, info);
                        dm_kill_unmapped_request(clone, r);
                } else if (r == DM_MAPIO_REMAPPED)
                        dm_dispatch_request(clone);
                else if (r == DM_MAPIO_REQUEUE) {
-                       mempool_free(mpio, m->mpio_pool);
+                       clear_mapinfo(m, info);
                        dm_requeue_unmapped_request(clone);
                }
        }
@@ -908,20 +928,16 @@ static int multipath_map(struct dm_target *ti, struct request *clone,
                         union map_info *map_context)
 {
        int r;
-       struct dm_mpath_io *mpio;
        struct multipath *m = (struct multipath *) ti->private;
 
-       mpio = mempool_alloc(m->mpio_pool, GFP_ATOMIC);
-       if (!mpio)
+       if (set_mapinfo(m, map_context) < 0)
                /* ENOMEM, requeue */
                return DM_MAPIO_REQUEUE;
-       memset(mpio, 0, sizeof(*mpio));
 
-       map_context->ptr = mpio;
        clone->cmd_flags |= REQ_FAILFAST_TRANSPORT;
-       r = map_io(m, clone, mpio, 0);
+       r = map_io(m, clone, map_context, 0);
        if (r < 0 || r == DM_MAPIO_REQUEUE)
-               mempool_free(mpio, m->mpio_pool);
+               clear_mapinfo(m, map_context);
 
        return r;
 }
@@ -1261,13 +1277,15 @@ static int multipath_end_io(struct dm_target *ti, struct request *clone,
        struct path_selector *ps;
        int r;
 
+       BUG_ON(!mpio);
+
        r  = do_end_io(m, clone, error, mpio);
        if (pgpath) {
                ps = &pgpath->pg->ps;
                if (ps->type->end_io)
                        ps->type->end_io(ps, &pgpath->path, mpio->nr_bytes);
        }
-       mempool_free(mpio, m->mpio_pool);
+       clear_mapinfo(m, map_context);
 
        return r;
 }