[PATCH] blk_queue_start_tag() shared map race fix
authorJens Axboe <axboe@kernel.dk>
Thu, 21 Sep 2006 18:37:22 +0000 (20:37 +0200)
committerJens Axboe <axboe@nelson.home.kernel.dk>
Sat, 30 Sep 2006 18:52:34 +0000 (20:52 +0200)
If we share the tag map between two or more queues, then we cannot
use __set_bit() to set the bit. In fact we need to make sure we
atomically acquire this tag, so loop using test_and_set_bit() to
protect from that.

Noticed by Mike Christie <michaelc@cs.wisc.edu>

Signed-off-by: Jens Axboe <axboe@kernel.dk>
block/ll_rw_blk.c

index f757ed4..83425fb 100644 (file)
@@ -1171,11 +1171,16 @@ int blk_queue_start_tag(request_queue_t *q, struct request *rq)
                BUG();
        }
 
-       tag = find_first_zero_bit(bqt->tag_map, bqt->max_depth);
-       if (tag >= bqt->max_depth)
-               return 1;
+       /*
+        * Protect against shared tag maps, as we may not have exclusive
+        * access to the tag map.
+        */
+       do {
+               tag = find_first_zero_bit(bqt->tag_map, bqt->max_depth);
+               if (tag >= bqt->max_depth)
+                       return 1;
 
-       __set_bit(tag, bqt->tag_map);
+       } while (test_and_set_bit(tag, bqt->tag_map));
 
        rq->cmd_flags |= REQ_QUEUED;
        rq->tag = tag;