aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/cciss.c
diff options
context:
space:
mode:
authorAndrew Patterson <andrew.patterson@hp.com>2009-09-17 14:46:58 -0400
committerJens Axboe <jens.axboe@oracle.com>2009-10-01 15:15:41 -0400
commitb368c9dd65984d1860b97bff77644c0e3e46df96 (patch)
tree003e31b2bb29eff630c3c156e08f4eaea7d7b6e2 /drivers/block/cciss.c
parentc64bebcd7f33a6260b6d4c9999f797a633a3fa1c (diff)
cciss: Use one scan thread per controller and fix hang during rmmod
Replace the use of one scan kthread per controller with one per driver. Use a queue to hold a list of controllers that need to be rescanned with routines to add and remove controllers from the queue. Fix locking and completion handling to prevent a hang during rmmod. Signed-off-by: Andrew Patterson <andrew.patterson@hp.com> Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com> Acked-by: Mike Miller <mike.miller@hp.com> Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Diffstat (limited to 'drivers/block/cciss.c')
-rw-r--r--drivers/block/cciss.c156
1 files changed, 136 insertions, 20 deletions
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index f162f96c36e6..4fb63b898798 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -40,6 +40,7 @@
40#include <linux/hdreg.h> 40#include <linux/hdreg.h>
41#include <linux/spinlock.h> 41#include <linux/spinlock.h>
42#include <linux/compat.h> 42#include <linux/compat.h>
43#include <linux/mutex.h>
43#include <asm/uaccess.h> 44#include <asm/uaccess.h>
44#include <asm/io.h> 45#include <asm/io.h>
45 46
@@ -156,6 +157,10 @@ static struct board_type products[] = {
156 157
157static ctlr_info_t *hba[MAX_CTLR]; 158static ctlr_info_t *hba[MAX_CTLR];
158 159
160static struct task_struct *cciss_scan_thread;
161static DEFINE_MUTEX(scan_mutex);
162static LIST_HEAD(scan_q);
163
159static void do_cciss_request(struct request_queue *q); 164static void do_cciss_request(struct request_queue *q);
160static irqreturn_t do_cciss_intr(int irq, void *dev_id); 165static irqreturn_t do_cciss_intr(int irq, void *dev_id);
161static int cciss_open(struct block_device *bdev, fmode_t mode); 166static int cciss_open(struct block_device *bdev, fmode_t mode);
@@ -3233,20 +3238,121 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id)
3233 return IRQ_HANDLED; 3238 return IRQ_HANDLED;
3234} 3239}
3235 3240
3241/**
3242 * add_to_scan_list() - add controller to rescan queue
3243 * @h: Pointer to the controller.
3244 *
3245 * Adds the controller to the rescan queue if not already on the queue.
3246 *
3247 * returns 1 if added to the queue, 0 if skipped (could be on the
3248 * queue already, or the controller could be initializing or shutting
3249 * down).
3250 **/
3251static int add_to_scan_list(struct ctlr_info *h)
3252{
3253 struct ctlr_info *test_h;
3254 int found = 0;
3255 int ret = 0;
3256
3257 if (h->busy_initializing)
3258 return 0;
3259
3260 if (!mutex_trylock(&h->busy_shutting_down))
3261 return 0;
3262
3263 mutex_lock(&scan_mutex);
3264 list_for_each_entry(test_h, &scan_q, scan_list) {
3265 if (test_h == h) {
3266 found = 1;
3267 break;
3268 }
3269 }
3270 if (!found && !h->busy_scanning) {
3271 INIT_COMPLETION(h->scan_wait);
3272 list_add_tail(&h->scan_list, &scan_q);
3273 ret = 1;
3274 }
3275 mutex_unlock(&scan_mutex);
3276 mutex_unlock(&h->busy_shutting_down);
3277
3278 return ret;
3279}
3280
3281/**
3282 * remove_from_scan_list() - remove controller from rescan queue
3283 * @h: Pointer to the controller.
3284 *
3285 * Removes the controller from the rescan queue if present. Blocks if
3286 * the controller is currently conducting a rescan.
3287 **/
3288static void remove_from_scan_list(struct ctlr_info *h)
3289{
3290 struct ctlr_info *test_h, *tmp_h;
3291 int scanning = 0;
3292
3293 mutex_lock(&scan_mutex);
3294 list_for_each_entry_safe(test_h, tmp_h, &scan_q, scan_list) {
3295 if (test_h == h) {
3296 list_del(&h->scan_list);
3297 complete_all(&h->scan_wait);
3298 mutex_unlock(&scan_mutex);
3299 return;
3300 }
3301 }
3302 if (&h->busy_scanning)
3303 scanning = 0;
3304 mutex_unlock(&scan_mutex);
3305
3306 if (scanning)
3307 wait_for_completion(&h->scan_wait);
3308}
3309
3310/**
3311 * scan_thread() - kernel thread used to rescan controllers
3312 * @data: Ignored.
3313 *
3314 * A kernel thread used scan for drive topology changes on
3315 * controllers. The thread processes only one controller at a time
3316 * using a queue. Controllers are added to the queue using
3317 * add_to_scan_list() and removed from the queue either after done
3318 * processing or using remove_from_scan_list().
3319 *
3320 * returns 0.
3321 **/
3236static int scan_thread(void *data) 3322static int scan_thread(void *data)
3237{ 3323{
3238 ctlr_info_t *h = data; 3324 struct ctlr_info *h;
3239 int rc;
3240 DECLARE_COMPLETION_ONSTACK(wait);
3241 h->rescan_wait = &wait;
3242 3325
3243 for (;;) { 3326 while (1) {
3244 rc = wait_for_completion_interruptible(&wait); 3327 set_current_state(TASK_INTERRUPTIBLE);
3328 schedule();
3245 if (kthread_should_stop()) 3329 if (kthread_should_stop())
3246 break; 3330 break;
3247 if (!rc) 3331
3248 rebuild_lun_table(h, 0); 3332 while (1) {
3333 mutex_lock(&scan_mutex);
3334 if (list_empty(&scan_q)) {
3335 mutex_unlock(&scan_mutex);
3336 break;
3337 }
3338
3339 h = list_entry(scan_q.next,
3340 struct ctlr_info,
3341 scan_list);
3342 list_del(&h->scan_list);
3343 h->busy_scanning = 1;
3344 mutex_unlock(&scan_mutex);
3345
3346 if (h) {
3347 rebuild_lun_table(h, 0);
3348 complete_all(&h->scan_wait);
3349 mutex_lock(&scan_mutex);
3350 h->busy_scanning = 0;
3351 mutex_unlock(&scan_mutex);
3352 }
3353 }
3249 } 3354 }
3355
3250 return 0; 3356 return 0;
3251} 3357}
3252 3358
@@ -3269,8 +3375,8 @@ static int check_for_unit_attention(ctlr_info_t *h, CommandList_struct *c)
3269 case REPORT_LUNS_CHANGED: 3375 case REPORT_LUNS_CHANGED:
3270 printk(KERN_WARNING "cciss%d: report LUN data " 3376 printk(KERN_WARNING "cciss%d: report LUN data "
3271 "changed\n", h->ctlr); 3377 "changed\n", h->ctlr);
3272 if (h->rescan_wait) 3378 add_to_scan_list(h);
3273 complete(h->rescan_wait); 3379 wake_up_process(cciss_scan_thread);
3274 return 1; 3380 return 1;
3275 break; 3381 break;
3276 case POWER_OR_RESET: 3382 case POWER_OR_RESET:
@@ -3919,6 +4025,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
3919 hba[i]->busy_initializing = 1; 4025 hba[i]->busy_initializing = 1;
3920 INIT_HLIST_HEAD(&hba[i]->cmpQ); 4026 INIT_HLIST_HEAD(&hba[i]->cmpQ);
3921 INIT_HLIST_HEAD(&hba[i]->reqQ); 4027 INIT_HLIST_HEAD(&hba[i]->reqQ);
4028 mutex_init(&hba[i]->busy_shutting_down);
3922 4029
3923 if (cciss_pci_init(hba[i], pdev) != 0) 4030 if (cciss_pci_init(hba[i], pdev) != 0)
3924 goto clean0; 4031 goto clean0;
@@ -3927,6 +4034,8 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
3927 hba[i]->ctlr = i; 4034 hba[i]->ctlr = i;
3928 hba[i]->pdev = pdev; 4035 hba[i]->pdev = pdev;
3929 4036
4037 init_completion(&hba[i]->scan_wait);
4038
3930 if (cciss_create_hba_sysfs_entry(hba[i])) 4039 if (cciss_create_hba_sysfs_entry(hba[i]))
3931 goto clean0; 4040 goto clean0;
3932 4041
@@ -4036,14 +4145,8 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
4036 4145
4037 hba[i]->cciss_max_sectors = 2048; 4146 hba[i]->cciss_max_sectors = 2048;
4038 4147
4039 hba[i]->busy_initializing = 0;
4040
4041 rebuild_lun_table(hba[i], 1); 4148 rebuild_lun_table(hba[i], 1);
4042 hba[i]->cciss_scan_thread = kthread_run(scan_thread, hba[i], 4149 hba[i]->busy_initializing = 0;
4043 "cciss_scan%02d", i);
4044 if (IS_ERR(hba[i]->cciss_scan_thread))
4045 return PTR_ERR(hba[i]->cciss_scan_thread);
4046
4047 return 1; 4150 return 1;
4048 4151
4049clean4: 4152clean4:
@@ -4126,8 +4229,9 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev)
4126 return; 4229 return;
4127 } 4230 }
4128 4231
4129 kthread_stop(hba[i]->cciss_scan_thread); 4232 mutex_lock(&hba[i]->busy_shutting_down);
4130 4233
4234 remove_from_scan_list(hba[i]);
4131 remove_proc_entry(hba[i]->devname, proc_cciss); 4235 remove_proc_entry(hba[i]->devname, proc_cciss);
4132 unregister_blkdev(hba[i]->major, hba[i]->devname); 4236 unregister_blkdev(hba[i]->major, hba[i]->devname);
4133 4237
@@ -4174,6 +4278,7 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev)
4174 pci_release_regions(pdev); 4278 pci_release_regions(pdev);
4175 pci_set_drvdata(pdev, NULL); 4279 pci_set_drvdata(pdev, NULL);
4176 cciss_destroy_hba_sysfs_entry(hba[i]); 4280 cciss_destroy_hba_sysfs_entry(hba[i]);
4281 mutex_unlock(&hba[i]->busy_shutting_down);
4177 free_hba(i); 4282 free_hba(i);
4178} 4283}
4179 4284
@@ -4206,15 +4311,25 @@ static int __init cciss_init(void)
4206 if (err) 4311 if (err)
4207 return err; 4312 return err;
4208 4313
4314 /* Start the scan thread */
4315 cciss_scan_thread = kthread_run(scan_thread, NULL, "cciss_scan");
4316 if (IS_ERR(cciss_scan_thread)) {
4317 err = PTR_ERR(cciss_scan_thread);
4318 goto err_bus_unregister;
4319 }
4320
4209 /* Register for our PCI devices */ 4321 /* Register for our PCI devices */
4210 err = pci_register_driver(&cciss_pci_driver); 4322 err = pci_register_driver(&cciss_pci_driver);
4211 if (err) 4323 if (err)
4212 goto err_bus_register; 4324 goto err_thread_stop;
4213 4325
4214 return 0; 4326 return 0;
4215 4327
4216err_bus_register: 4328err_thread_stop:
4329 kthread_stop(cciss_scan_thread);
4330err_bus_unregister:
4217 bus_unregister(&cciss_bus_type); 4331 bus_unregister(&cciss_bus_type);
4332
4218 return err; 4333 return err;
4219} 4334}
4220 4335
@@ -4231,6 +4346,7 @@ static void __exit cciss_cleanup(void)
4231 cciss_remove_one(hba[i]->pdev); 4346 cciss_remove_one(hba[i]->pdev);
4232 } 4347 }
4233 } 4348 }
4349 kthread_stop(cciss_scan_thread);
4234 remove_proc_entry("driver/cciss", NULL); 4350 remove_proc_entry("driver/cciss", NULL);
4235 bus_unregister(&cciss_bus_type); 4351 bus_unregister(&cciss_bus_type);
4236} 4352}