Commit 5309cb38 authored by Jens Axboe's avatar Jens Axboe

Add queue resizing support

Just get rid of the preallocated command map, use the slab cache
to get/free commands instead.

Original patch from FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>,
changed by me to not use a mempool.
Signed-off-by: default avatarJens Axboe <jens.axboe@oracle.com>
parent 3862153b
...@@ -33,8 +33,6 @@ ...@@ -33,8 +33,6 @@
static char bsg_version[] = "block layer sg (bsg) 0.4"; static char bsg_version[] = "block layer sg (bsg) 0.4";
struct bsg_command;
struct bsg_device { struct bsg_device {
struct gendisk *disk; struct gendisk *disk;
request_queue_t *queue; request_queue_t *queue;
...@@ -46,8 +44,6 @@ struct bsg_device { ...@@ -46,8 +44,6 @@ struct bsg_device {
int minor; int minor;
int queued_cmds; int queued_cmds;
int done_cmds; int done_cmds;
unsigned long *cmd_bitmap;
struct bsg_command *cmd_map;
wait_queue_head_t wq_done; wait_queue_head_t wq_done;
wait_queue_head_t wq_free; wait_queue_head_t wq_free;
char name[BDEVNAME_SIZE]; char name[BDEVNAME_SIZE];
...@@ -60,14 +56,7 @@ enum { ...@@ -60,14 +56,7 @@ enum {
BSG_F_WRITE_PERM = 2, BSG_F_WRITE_PERM = 2,
}; };
/* #define BSG_DEFAULT_CMDS 64
* 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))
#undef BSG_DEBUG #undef BSG_DEBUG
...@@ -94,6 +83,8 @@ static struct hlist_head bsg_device_list[BSG_LIST_SIZE]; ...@@ -94,6 +83,8 @@ static struct hlist_head bsg_device_list[BSG_LIST_SIZE];
static struct class *bsg_class; static struct class *bsg_class;
static LIST_HEAD(bsg_class_list); static LIST_HEAD(bsg_class_list);
static struct kmem_cache *bsg_cmd_cachep;
/* /*
* our internal command type * our internal command type
*/ */
...@@ -111,14 +102,12 @@ struct bsg_command { ...@@ -111,14 +102,12 @@ struct bsg_command {
static void bsg_free_command(struct bsg_command *bc) static void bsg_free_command(struct bsg_command *bc)
{ {
struct bsg_device *bd = bc->bd; struct bsg_device *bd = bc->bd;
unsigned long bitnr = bc - bd->cmd_map;
unsigned long flags; unsigned long flags;
dprintk("%s: command bit offset %lu\n", bd->name, bitnr); kmem_cache_free(bsg_cmd_cachep, bc);
spin_lock_irqsave(&bd->lock, flags); spin_lock_irqsave(&bd->lock, flags);
bd->queued_cmds--; bd->queued_cmds--;
__clear_bit(bitnr, bd->cmd_bitmap);
spin_unlock_irqrestore(&bd->lock, flags); spin_unlock_irqrestore(&bd->lock, flags);
wake_up(&bd->wq_free); wake_up(&bd->wq_free);
...@@ -127,32 +116,29 @@ static void bsg_free_command(struct bsg_command *bc) ...@@ -127,32 +116,29 @@ static void bsg_free_command(struct bsg_command *bc)
static struct bsg_command *__bsg_alloc_command(struct bsg_device *bd) static struct bsg_command *__bsg_alloc_command(struct bsg_device *bd)
{ {
struct bsg_command *bc = NULL; struct bsg_command *bc = NULL;
unsigned long *map;
int free_nr;
spin_lock_irq(&bd->lock); spin_lock_irq(&bd->lock);
if (bd->queued_cmds >= bd->max_queue) if (bd->queued_cmds >= bd->max_queue)
goto out; 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++; bd->queued_cmds++;
free_nr += ffz(*map);
__set_bit(free_nr, bd->cmd_bitmap);
spin_unlock_irq(&bd->lock); spin_unlock_irq(&bd->lock);
bc = bd->cmd_map + free_nr; bc = kmem_cache_alloc(bsg_cmd_cachep, GFP_USER);
if (unlikely(!bc)) {
spin_lock_irq(&bd->lock);
goto alloc_fail;
}
memset(bc, 0, sizeof(*bc)); memset(bc, 0, sizeof(*bc));
bc->bd = bd; bc->bd = bd;
INIT_LIST_HEAD(&bc->list); 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; return bc;
alloc_fail:
bd->queued_cmds--;
out: out:
dprintk("%s: failed (depth %d)\n", bd->name, bd->queued_cmds);
spin_unlock_irq(&bd->lock); spin_unlock_irq(&bd->lock);
return bc; return bc;
} }
...@@ -356,8 +342,8 @@ static void bsg_rq_end_io(struct request *rq, int uptodate) ...@@ -356,8 +342,8 @@ static void bsg_rq_end_io(struct request *rq, int uptodate)
struct bsg_device *bd = bc->bd; struct bsg_device *bd = bc->bd;
unsigned long flags; unsigned long flags;
dprintk("%s: finished rq %p bc %p, bio %p offset %Zd stat %d\n", dprintk("%s: finished rq %p bc %p, bio %p stat %d\n",
bd->name, rq, bc, bc->bio, bc - bd->cmd_map, uptodate); bd->name, rq, bc, bc->bio, uptodate);
bc->hdr.duration = jiffies_to_msecs(jiffies - bc->hdr.duration); bc->hdr.duration = jiffies_to_msecs(jiffies - bc->hdr.duration);
...@@ -703,21 +689,9 @@ bsg_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) ...@@ -703,21 +689,9 @@ bsg_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
return bytes_read; return bytes_read;
} }
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);
kfree(bd);
}
static struct bsg_device *bsg_alloc_device(void) static struct bsg_device *bsg_alloc_device(void)
{ {
struct bsg_command *cmd_map;
unsigned long *cmd_bitmap;
struct bsg_device *bd; struct bsg_device *bd;
int bits;
bd = kzalloc(sizeof(struct bsg_device), GFP_KERNEL); bd = kzalloc(sizeof(struct bsg_device), GFP_KERNEL);
if (unlikely(!bd)) if (unlikely(!bd))
...@@ -725,19 +699,7 @@ static struct bsg_device *bsg_alloc_device(void) ...@@ -725,19 +699,7 @@ static struct bsg_device *bsg_alloc_device(void)
spin_lock_init(&bd->lock); spin_lock_init(&bd->lock);
bd->max_queue = BSG_CMDS; bd->max_queue = BSG_DEFAULT_CMDS;
bits = (BSG_CMDS / BSG_CMDS_PER_LONG) + 1;
cmd_bitmap = kzalloc(bits * sizeof(unsigned long), GFP_KERNEL);
if (!cmd_bitmap)
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->busy_list);
INIT_LIST_HEAD(&bd->done_list); INIT_LIST_HEAD(&bd->done_list);
...@@ -746,12 +708,6 @@ static struct bsg_device *bsg_alloc_device(void) ...@@ -746,12 +708,6 @@ static struct bsg_device *bsg_alloc_device(void)
init_waitqueue_head(&bd->wq_free); init_waitqueue_head(&bd->wq_free);
init_waitqueue_head(&bd->wq_done); init_waitqueue_head(&bd->wq_done);
return bd; return bd;
out_free_bitmap:
kfree(cmd_bitmap);
out_free_bd:
kfree(bd);
return NULL;
} }
static int bsg_put_device(struct bsg_device *bd) static int bsg_put_device(struct bsg_device *bd)
...@@ -779,7 +735,7 @@ static int bsg_put_device(struct bsg_device *bd) ...@@ -779,7 +735,7 @@ static int bsg_put_device(struct bsg_device *bd)
blk_put_queue(bd->queue); blk_put_queue(bd->queue);
hlist_del(&bd->dev_list); hlist_del(&bd->dev_list);
bsg_free_device(bd); kfree(bd);
out: out:
mutex_unlock(&bsg_mutex); mutex_unlock(&bsg_mutex);
return ret; return ret;
...@@ -918,15 +874,17 @@ bsg_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -918,15 +874,17 @@ bsg_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
*/ */
case SG_GET_COMMAND_Q: case SG_GET_COMMAND_Q:
return put_user(bd->max_queue, uarg); return put_user(bd->max_queue, uarg);
case SG_SET_COMMAND_Q: { case SG_SET_COMMAND_Q: {
int queue; int queue;
if (get_user(queue, uarg)) if (get_user(queue, uarg))
return -EFAULT; return -EFAULT;
if (queue > BSG_CMDS || queue < 1) if (queue < 1)
return -EINVAL; return -EINVAL;
spin_lock_irq(&bd->lock);
bd->max_queue = queue; bd->max_queue = queue;
spin_unlock_irq(&bd->lock);
return 0; return 0;
} }
...@@ -1035,15 +993,25 @@ static int __init bsg_init(void) ...@@ -1035,15 +993,25 @@ static int __init bsg_init(void)
{ {
int ret, i; int ret, i;
bsg_cmd_cachep = kmem_cache_create("bsg_cmd",
sizeof(struct bsg_command), 0, 0, NULL, NULL);
if (!bsg_cmd_cachep) {
printk(KERN_ERR "bsg: failed creating slab cache\n");
return -ENOMEM;
}
for (i = 0; i < BSG_LIST_SIZE; i++) for (i = 0; i < BSG_LIST_SIZE; i++)
INIT_HLIST_HEAD(&bsg_device_list[i]); INIT_HLIST_HEAD(&bsg_device_list[i]);
bsg_class = class_create(THIS_MODULE, "bsg"); bsg_class = class_create(THIS_MODULE, "bsg");
if (IS_ERR(bsg_class)) if (IS_ERR(bsg_class)) {
kmem_cache_destroy(bsg_cmd_cachep);
return PTR_ERR(bsg_class); return PTR_ERR(bsg_class);
}
ret = register_chrdev(BSG_MAJOR, "bsg", &bsg_fops); ret = register_chrdev(BSG_MAJOR, "bsg", &bsg_fops);
if (ret) { if (ret) {
kmem_cache_destroy(bsg_cmd_cachep);
class_destroy(bsg_class); class_destroy(bsg_class);
return ret; return ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment