History

[SCSI] block: add support for shared tag maps

The current block queue implementation already contains most of the machinery for shared tag maps. The only remaining pieces are a way to allocate and destroy a tag map independently of the queues (so that the maps can be managed on the life cycle of the overseeing entity)

James Bottomley committed 20 years ago

Commit 492dfb41 parent f19eaa72 files · +90 −21Browse files

Unified · Split

2 files
  1. block/ll_rw_blk.c +88 −21
  2. include/linux/blkdev.h +2 −0
block/ll_rw_blk.c+88−21
@@ -848,21 +848,18 @@ struct request *blk_queue_find_tag(request_queue_t *q, int tag) · 847 unmodified lines
848848 EXPORT_SYMBOL(blk_queue_find_tag);
849849
850850 /**
851− * __blk_queue_free_tags - release tag maintenance info
852− * @q: the request queue for the device
851+ * __blk_free_tags - release a given set of tag maintenance info
852+ * @bqt: the tag map to free
853853 *
854− * Notes:
855− * blk_cleanup_queue() will take care of calling this function, if tagging
856− * has been used. So there's no need to call this directly.
857− **/
858−static void __blk_queue_free_tags(request_queue_t *q)
854+ * Tries to free the specified @bqt@. Returns true if it was
855+ * actually freed and false if there are still references using it
856+ */
857+static int __blk_free_tags(struct blk_queue_tag *bqt)
859858 {
860− struct blk_queue_tag *bqt = q->queue_tags;
861−
862− if (!bqt)
863− return;
859+ int retval;
864860
865− if (atomic_dec_and_test(&bqt->refcnt)) {
861+ retval = atomic_dec_and_test(&bqt->refcnt);
862+ if (retval) {
866863 BUG_ON(bqt->busy);
867864 BUG_ON(!list_empty(&bqt->busy_list));
868865
@@ -873,12 +870,49 @@ static void __blk_queue_free_tags(request_queue_t *q) · 4 unmodified lines
873870 bqt->tag_map = NULL;
874871
875872 kfree(bqt);
873+
876874 }
877875
876+ return retval;
877+}
878+
879+/**
880+ * __blk_queue_free_tags - release tag maintenance info
881+ * @q: the request queue for the device
882+ *
883+ * Notes:
884+ * blk_cleanup_queue() will take care of calling this function, if tagging
885+ * has been used. So there's no need to call this directly.
886+ **/
887+static void __blk_queue_free_tags(request_queue_t *q)
888+{
889+ struct blk_queue_tag *bqt = q->queue_tags;
890+
891+ if (!bqt)
892+ return;
893+
894+ __blk_free_tags(bqt);
895+
878896 q->queue_tags = NULL;
879897 q->queue_flags &= ~(1 << QUEUE_FLAG_QUEUED);
880898 }
881899
900+
901+/**
902+ * blk_free_tags - release a given set of tag maintenance info
903+ * @bqt: the tag map to free
904+ *
905+ * For externally managed @bqt@ frees the map. Callers of this
906+ * function must guarantee to have released all the queues that
907+ * might have been using this tag map.
908+ */
909+void blk_free_tags(struct blk_queue_tag *bqt)
910+{
911+ if (unlikely(!__blk_free_tags(bqt)))
912+ BUG();
913+}
914+EXPORT_SYMBOL(blk_free_tags);
915+
882916 /**
883917 * blk_queue_free_tags - release tag maintenance info
884918 * @q: the request queue for the device
@@ -901,7 +935,7 @@ init_tag_map(request_queue_t *q, struct blk_queue_tag *tags, int depth) · 16 unmodified lines
901935 unsigned long *tag_map;
902936 int nr_ulongs;
903937
904− if (depth > q->nr_requests * 2) {
938+ if (q && depth > q->nr_requests * 2) {
905939 depth = q->nr_requests * 2;
906940 printk(KERN_ERR "%s: adjusted depth to %d\n",
907941 __FUNCTION__, depth);
@@ -927,6 +961,38 @@ fail: · 19 unmodified lines
927961 return -ENOMEM;
928962 }
929963
964+static struct blk_queue_tag *__blk_queue_init_tags(struct request_queue *q,
965+ int depth)
966+{
967+ struct blk_queue_tag *tags;
968+
969+ tags = kmalloc(sizeof(struct blk_queue_tag), GFP_ATOMIC);
970+ if (!tags)
971+ goto fail;
972+
973+ if (init_tag_map(q, tags, depth))
974+ goto fail;
975+
976+ INIT_LIST_HEAD(&tags->busy_list);
977+ tags->busy = 0;
978+ atomic_set(&tags->refcnt, 1);
979+ return tags;
980+fail:
981+ kfree(tags);
982+ return NULL;
983+}
984+
985+/**
986+ * blk_init_tags - initialize the tag info for an external tag map
987+ * @depth: the maximum queue depth supported
988+ * @tags: the tag to use
989+ **/
990+struct blk_queue_tag *blk_init_tags(int depth)
991+{
992+ return __blk_queue_init_tags(NULL, depth);
993+}
994+EXPORT_SYMBOL(blk_init_tags);
995+
930996 /**
931997 * blk_queue_init_tags - initialize the queue tag info
932998 * @q: the request queue for the device
@@ -941,16 +1007,10 @@ int blk_queue_init_tags(request_queue_t *q, int depth, · 8 unmodified lines
9411007 BUG_ON(tags && q->queue_tags && tags != q->queue_tags);
9421008
9431009 if (!tags && !q->queue_tags) {
944− tags = kmalloc(sizeof(struct blk_queue_tag), GFP_ATOMIC);
945− if (!tags)
946− goto fail;
1010+ tags = __blk_queue_init_tags(q, depth);
9471011
948− if (init_tag_map(q, tags, depth))
1012+ if (!tags)
9491013 goto fail;
950−
951− INIT_LIST_HEAD(&tags->busy_list);
952− tags->busy = 0;
953− atomic_set(&tags->refcnt, 1);
9541014 } else if (q->queue_tags) {
9551015 if ((rc = blk_queue_resize_tags(q, depth)))
9561016 return rc;
@@ -1001,6 +1061,13 @@ int blk_queue_resize_tags(request_queue_t *q, int new_depth) · 44 unmodified lines
10011061 return 0;
10021062 }
10031063
1064+ /*
1065+ * Currently cannot replace a shared tag map with a new
1066+ * one, so error out if this is the case
1067+ */
1068+ if (atomic_read(&bqt->refcnt) != 1)
1069+ return -EBUSY;
1070+
10041071 /*
10051072 * save the old state info, so we can copy it back
10061073 */
include/linux/blkdev.h+2−0
@@ -746,6 +746,8 @@ extern void blk_queue_free_tags(request_queue_t *); · 745 unmodified lines
746746 extern int blk_queue_resize_tags(request_queue_t *, int);
747747 extern void blk_queue_invalidate_tags(request_queue_t *);
748748 extern long blk_congestion_wait(int rw, long timeout);
749+extern struct blk_queue_tag *blk_init_tags(int);
750+extern void blk_free_tags(struct blk_queue_tag *);
749751
750752 extern void blk_rq_bio_prep(request_queue_t *, struct request *, struct bio *);
751753 extern int blkdev_issue_flush(struct block_device *, sector_t *);