From d45ac4fa8f277e1ec5acfb67ce5d6406555760cf Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Mon, 31 Mar 2008 10:03:38 +0900 Subject: [SCSI] bsg: takes a ref to struct device in fops->open bsg_register_queue() takes a ref to struct device that a caller passes. For example, bsg takes a ref to the sdev_gendev for scsi devices. However, bsg doesn't inrease the refcount in fops->open. So while an application opens a bsg device, the scsi device that the bsg device holds can go away (bsg also takes a ref to a queue, but it doesn't prevent the device from going away). With this patch, bsg increases the refcount of struct device in fops->open and decreases it in fops->release. Signed-off-by: FUJITA Tomonori Signed-off-by: James Bottomley --- block/bsg.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'block') diff --git a/block/bsg.c b/block/bsg.c index 8917c5174dc..d8e0cb8dd6b 100644 --- a/block/bsg.c +++ b/block/bsg.c @@ -705,6 +705,7 @@ static struct bsg_device *bsg_alloc_device(void) static int bsg_put_device(struct bsg_device *bd) { int ret = 0; + struct device *dev = bd->queue->bsg_dev.dev; mutex_lock(&bsg_mutex); @@ -730,6 +731,7 @@ static int bsg_put_device(struct bsg_device *bd) kfree(bd); out: mutex_unlock(&bsg_mutex); + put_device(dev); return ret; } @@ -789,21 +791,27 @@ static struct bsg_device *bsg_get_device(struct inode *inode, struct file *file) struct bsg_device *bd; struct bsg_class_device *bcd; - bd = __bsg_get_device(iminor(inode)); - if (bd) - return bd; - /* * find the class device */ mutex_lock(&bsg_mutex); bcd = idr_find(&bsg_minor_idr, iminor(inode)); + if (bcd) + get_device(bcd->dev); mutex_unlock(&bsg_mutex); if (!bcd) return ERR_PTR(-ENODEV); - return bsg_add_device(inode, bcd->queue, file); + bd = __bsg_get_device(iminor(inode)); + if (bd) + return bd; + + bd = bsg_add_device(inode, bcd->queue, file); + if (IS_ERR(bd)) + put_device(bcd->dev); + + return bd; } static int bsg_open(struct inode *inode, struct file *file) @@ -942,7 +950,6 @@ void bsg_unregister_queue(struct request_queue *q) class_device_unregister(bcd->class_dev); put_device(bcd->dev); bcd->class_dev = NULL; - bcd->dev = NULL; mutex_unlock(&bsg_mutex); } EXPORT_SYMBOL_GPL(bsg_unregister_queue); -- cgit v1.2.3-70-g09d2 From c3ff1b90d8924dd1c55c3b56a79bfc563ace4a42 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Mon, 31 Mar 2008 10:03:39 +0900 Subject: [SCSI] bsg: replace kobject_get with blk_get_queue Both takes a ref to a queue. But blk_get_queue checks QUEUE_FLAG_DEAD and is more appropriate interface here. Signed-off-by: FUJITA Tomonori Signed-off-by: James Bottomley --- block/bsg.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'block') diff --git a/block/bsg.c b/block/bsg.c index d8e0cb8dd6b..e2c65a150a7 100644 --- a/block/bsg.c +++ b/block/bsg.c @@ -740,16 +740,21 @@ static struct bsg_device *bsg_add_device(struct inode *inode, struct file *file) { struct bsg_device *bd; + int ret; #ifdef BSG_DEBUG unsigned char buf[32]; #endif + ret = blk_get_queue(rq); + if (ret) + return ERR_PTR(-ENXIO); bd = bsg_alloc_device(); - if (!bd) + if (!bd) { + blk_put_queue(rq); return ERR_PTR(-ENOMEM); + } bd->queue = rq; - kobject_get(&rq->kobj); bsg_set_block(bd, file); atomic_set(&bd->ref_count, 1); -- cgit v1.2.3-70-g09d2 From 43ac9e62c4a0a47fe3de1f1eb9ca7b8c91dce234 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Mon, 31 Mar 2008 10:03:40 +0900 Subject: [SCSI] bsg: use better helper list functions This replace hlist_for_each and list_entry with hlist_for_each_entry and list_first_entry respectively. Signed-off-by: FUJITA Tomonori Signed-off-by: James Bottomley --- block/bsg.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'block') diff --git a/block/bsg.c b/block/bsg.c index e2c65a150a7..b413318a7c5 100644 --- a/block/bsg.c +++ b/block/bsg.c @@ -368,7 +368,7 @@ static struct bsg_command *bsg_next_done_cmd(struct bsg_device *bd) spin_lock_irq(&bd->lock); if (bd->done_cmds) { - bc = list_entry(bd->done_list.next, struct bsg_command, list); + bc = list_first_entry(&bd->done_list, struct bsg_command, list); list_del(&bc->list); bd->done_cmds--; } @@ -772,21 +772,19 @@ static struct bsg_device *bsg_add_device(struct inode *inode, static struct bsg_device *__bsg_get_device(int minor) { - struct bsg_device *bd = NULL; + struct bsg_device *bd; struct hlist_node *entry; mutex_lock(&bsg_mutex); - hlist_for_each(entry, bsg_dev_idx_hash(minor)) { - bd = hlist_entry(entry, struct bsg_device, dev_list); + hlist_for_each_entry(bd, entry, bsg_dev_idx_hash(minor), dev_list) { if (bd->minor == minor) { atomic_inc(&bd->ref_count); - break; + goto found; } - - bd = NULL; } - + bd = NULL; +found: mutex_unlock(&bsg_mutex); return bd; } -- cgit v1.2.3-70-g09d2 From 842ea771c38a3f0f78bdb1b4d47881e6a210fc15 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Mon, 31 Mar 2008 10:03:41 +0900 Subject: [SCSI] bsg: remove minor in struct bsg_device minor in struct bsg_device is used as identifier to find the corresponding struct bsg_device_class. However, request_queuse can be used as identifier for that and the minor in struct bsg_device is unnecessary. Signed-off-by: FUJITA Tomonori Signed-off-by: James Bottomley --- block/bsg.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'block') diff --git a/block/bsg.c b/block/bsg.c index b413318a7c5..93399812421 100644 --- a/block/bsg.c +++ b/block/bsg.c @@ -37,7 +37,6 @@ struct bsg_device { struct list_head done_list; struct hlist_node dev_list; atomic_t ref_count; - int minor; int queued_cmds; int done_cmds; wait_queue_head_t wq_done; @@ -758,9 +757,8 @@ static struct bsg_device *bsg_add_device(struct inode *inode, bsg_set_block(bd, file); atomic_set(&bd->ref_count, 1); - bd->minor = iminor(inode); mutex_lock(&bsg_mutex); - hlist_add_head(&bd->dev_list, bsg_dev_idx_hash(bd->minor)); + hlist_add_head(&bd->dev_list, bsg_dev_idx_hash(iminor(inode))); strncpy(bd->name, rq->bsg_dev.class_dev->class_id, sizeof(bd->name) - 1); dprintk("bound to <%s>, max queue %d\n", @@ -770,7 +768,7 @@ static struct bsg_device *bsg_add_device(struct inode *inode, return bd; } -static struct bsg_device *__bsg_get_device(int minor) +static struct bsg_device *__bsg_get_device(int minor, struct request_queue *q) { struct bsg_device *bd; struct hlist_node *entry; @@ -778,7 +776,7 @@ static struct bsg_device *__bsg_get_device(int minor) mutex_lock(&bsg_mutex); hlist_for_each_entry(bd, entry, bsg_dev_idx_hash(minor), dev_list) { - if (bd->minor == minor) { + if (bd->queue == q) { atomic_inc(&bd->ref_count); goto found; } @@ -806,7 +804,7 @@ static struct bsg_device *bsg_get_device(struct inode *inode, struct file *file) if (!bcd) return ERR_PTR(-ENODEV); - bd = __bsg_get_device(iminor(inode)); + bd = __bsg_get_device(iminor(inode), bcd->queue); if (bd) return bd; -- cgit v1.2.3-70-g09d2 From 99773aab0377ee5bcaf37b7cd2577c3465422dab Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Mon, 31 Mar 2008 10:03:42 +0900 Subject: [SCSI] bsg: no need to set BSG_F_BLOCK bit in bsg_complete_all_commands Before bsg_complete_all_commands is called, BSG_F_BLOCK bit is always set. Signed-off-by: FUJITA Tomonori Signed-off-by: James Bottomley --- block/bsg.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'block') diff --git a/block/bsg.c b/block/bsg.c index 93399812421..302ac1f5af3 100644 --- a/block/bsg.c +++ b/block/bsg.c @@ -467,8 +467,6 @@ static int bsg_complete_all_commands(struct bsg_device *bd) dprintk("%s: entered\n", bd->name); - set_bit(BSG_F_BLOCK, &bd->flags); - /* * wait for all commands to complete */ -- cgit v1.2.3-70-g09d2