[PATCH] add bsg queue resize

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This enables bsg to resize the queue depth via
SG_SET_COMMAND_Q. bsg_command structures are allocated via mempool
because the previous way to use contiguous memory makes it difficult
to resize the queue depth when a bsg_device has outstanding commands.

Signed-off-by: FUJITA Tomonori <fujita.tomonori@xxxxxxxxxxxxx>
---
 block/bsg.c |  112 +++++++++++++++++++++++-----------------------------------
 1 files changed, 45 insertions(+), 67 deletions(-)

diff --git a/block/bsg.c b/block/bsg.c
index 9d77a0c..af46f54 100644
--- a/block/bsg.c
+++ b/block/bsg.c
@@ -33,8 +33,6 @@ #include <scsi/sg.h>
 
 static char bsg_version[] = "block layer sg (bsg) 0.4";
 
-struct bsg_command;
-
 struct bsg_device {
 	struct gendisk *disk;
 	request_queue_t *queue;
@@ -46,8 +44,7 @@ struct bsg_device {
 	int minor;
 	int queued_cmds;
 	int done_cmds;
-	unsigned long *cmd_bitmap;
-	struct bsg_command *cmd_map;
+	mempool_t *bsg_cmd_q;
 	wait_queue_head_t wq_done;
 	wait_queue_head_t wq_free;
 	char name[BDEVNAME_SIZE];
@@ -55,19 +52,26 @@ struct bsg_device {
 	unsigned long flags;
 };
 
+/*
+ * our internal command type
+ */
+struct bsg_command {
+	struct bsg_device *bd;
+	struct list_head list;
+	struct request *rq;
+	struct bio *bio;
+	int err;
+	struct sg_io_v4 hdr;
+	struct sg_io_v4 __user *uhdr;
+	char sense[SCSI_SENSE_BUFFERSIZE];
+};
+
 enum {
 	BSG_F_BLOCK		= 1,
 	BSG_F_WRITE_PERM	= 2,
 };
 
-/*
- * command allocation bitmap defines
- */
-#define BSG_CMDS_PAGE_ORDER	(1)
-#define BSG_CMDS_PER_LONG	(sizeof(unsigned long) * 8)
-#define BSG_CMDS_MASK		(BSG_CMDS_PER_LONG - 1)
-#define BSG_CMDS_BYTES		(PAGE_SIZE * (1 << BSG_CMDS_PAGE_ORDER))
-#define BSG_CMDS		(BSG_CMDS_BYTES / sizeof(struct bsg_command))
+#define BSG_DEFAULT_CMDS	(64)
 
 #undef BSG_DEBUG
 
@@ -94,31 +98,18 @@ static struct hlist_head bsg_device_list
 static struct class *bsg_class;
 static LIST_HEAD(bsg_class_list);
 
-/*
- * our internal command type
- */
-struct bsg_command {
-	struct bsg_device *bd;
-	struct list_head list;
-	struct request *rq;
-	struct bio *bio;
-	int err;
-	struct sg_io_v4 hdr;
-	struct sg_io_v4 __user *uhdr;
-	char sense[SCSI_SENSE_BUFFERSIZE];
-};
+static struct kmem_cache *bsg_cmd_cachep;
 
 static void bsg_free_command(struct bsg_command *bc)
 {
 	struct bsg_device *bd = bc->bd;
-	unsigned long bitnr = bc - bd->cmd_map;
 	unsigned long flags;
 
-	dprintk("%s: command bit offset %lu\n", bd->name, bitnr);
+	dprintk("%s: command free %p\n", bd->name, bc);
 
+	mempool_free(bc, bd->bsg_cmd_q);
 	spin_lock_irqsave(&bd->lock, flags);
 	bd->queued_cmds--;
-	__clear_bit(bitnr, bd->cmd_bitmap);
 	spin_unlock_irqrestore(&bd->lock, flags);
 
 	wake_up(&bd->wq_free);
@@ -127,29 +118,18 @@ static void bsg_free_command(struct bsg_
 static struct bsg_command *__bsg_alloc_command(struct bsg_device *bd)
 {
 	struct bsg_command *bc = NULL;
-	unsigned long *map;
-	int free_nr;
 
 	spin_lock_irq(&bd->lock);
-
 	if (bd->queued_cmds >= bd->max_queue)
 		goto out;
-
-	for (free_nr = 0, map = bd->cmd_bitmap; *map == ~0UL; map++)
-		free_nr += BSG_CMDS_PER_LONG;
-
-	BUG_ON(*map == ~0UL);
-
 	bd->queued_cmds++;
-	free_nr += ffz(*map);
-	__set_bit(free_nr, bd->cmd_bitmap);
 	spin_unlock_irq(&bd->lock);
 
-	bc = bd->cmd_map + free_nr;
+	bc = mempool_alloc(bd->bsg_cmd_q, GFP_NOWAIT);
 	memset(bc, 0, sizeof(*bc));
 	bc->bd = bd;
 	INIT_LIST_HEAD(&bc->list);
-	dprintk("%s: returning free cmd %p (bit %d)\n", bd->name, bc, free_nr);
+	dprintk("%s: returning free cmd %p\n", bd->name, bc);
 	return bc;
 out:
 	dprintk("%s: failed (depth %d)\n", bd->name, bd->queued_cmds);
@@ -356,8 +336,8 @@ static void bsg_rq_end_io(struct request
 	struct bsg_device *bd = bc->bd;
 	unsigned long flags;
 
-	dprintk("%s: finished rq %p bc %p, bio %p offset %Zd stat %d\n",
-		bd->name, rq, bc, bc->bio, bc - bd->cmd_map, uptodate);
+	dprintk("%s: finished rq %p bc %p, bio %p stat %d\n",
+		bd->name, rq, bc, bc->bio, uptodate);
 
 	bc->hdr.duration = jiffies_to_msecs(jiffies - bc->hdr.duration);
 
@@ -705,19 +685,13 @@ bsg_write(struct file *file, const char
 
 static void bsg_free_device(struct bsg_device *bd)
 {
-	if (bd->cmd_map)
-		free_pages((unsigned long) bd->cmd_map, BSG_CMDS_PAGE_ORDER);
-
-	kfree(bd->cmd_bitmap);
+	mempool_destroy(bd->bsg_cmd_q);
 	kfree(bd);
 }
 
 static struct bsg_device *bsg_alloc_device(void)
 {
-	struct bsg_command *cmd_map;
-	unsigned long *cmd_bitmap;
 	struct bsg_device *bd;
-	int bits;
 
 	bd = kzalloc(sizeof(struct bsg_device), GFP_KERNEL);
 	if (unlikely(!bd))
@@ -725,19 +699,10 @@ static struct bsg_device *bsg_alloc_devi
 
 	spin_lock_init(&bd->lock);
 
-	bd->max_queue = BSG_CMDS;
-
-	bits = (BSG_CMDS / BSG_CMDS_PER_LONG) + 1;
-	cmd_bitmap = kzalloc(bits * sizeof(unsigned long), GFP_KERNEL);
-	if (!cmd_bitmap)
+	bd->max_queue = BSG_DEFAULT_CMDS;
+	bd->bsg_cmd_q = mempool_create_slab_pool(bd->max_queue, bsg_cmd_cachep);
+	if (unlikely(!bd->bsg_cmd_q))
 		goto out_free_bd;
-	bd->cmd_bitmap = cmd_bitmap;
-
-	cmd_map = (void *) __get_free_pages(GFP_KERNEL | __GFP_ZERO,
-						BSG_CMDS_PAGE_ORDER);
-	if (!cmd_map)
-		goto out_free_bitmap;
-	bd->cmd_map = cmd_map;
 
 	INIT_LIST_HEAD(&bd->busy_list);
 	INIT_LIST_HEAD(&bd->done_list);
@@ -747,8 +712,6 @@ static struct bsg_device *bsg_alloc_devi
 	init_waitqueue_head(&bd->wq_done);
 	return bd;
 
-out_free_bitmap:
-	kfree(cmd_bitmap);
 out_free_bd:
 	kfree(bd);
 	return NULL;
@@ -918,15 +881,22 @@ bsg_ioctl(struct inode *inode, struct fi
 		 */
 	case SG_GET_COMMAND_Q:
 		return put_user(bd->max_queue, uarg);
-		case SG_SET_COMMAND_Q: {
-		int queue;
+	case SG_SET_COMMAND_Q: {
+		int queue, ret;
 
 		if (get_user(queue, uarg))
 			return -EFAULT;
-		if (queue > BSG_CMDS || queue < 1)
+
+		if (queue < 1)
 			return -EINVAL;
 
+		ret = mempool_resize(bd->bsg_cmd_q, queue, GFP_KERNEL);
+		if (ret)
+			return ret;
+
+		spin_lock_irq(&bd->lock);
 		bd->max_queue = queue;
+		spin_unlock_irq(&bd->lock);
 		return 0;
 	}
 
@@ -1048,6 +1018,14 @@ static int __init bsg_init(void)
 		return ret;
 	}
 
+	bsg_cmd_cachep = kmem_cache_create("bsg_cmd", sizeof(struct bsg_command),
+					   0, 0, NULL, NULL);
+	if (!bsg_cmd_cachep) {
+		class_destroy(bsg_class);
+		unregister_chrdev(BSG_MAJOR, "bsg");
+		return -ENOMEM;
+	}
+
 	printk(KERN_INFO "%s loaded\n", bsg_version);
 	return 0;
 }
-- 
1.4.3.2

-
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux