diff options
-rw-r--r-- | block/blk-ioc.c | 135 | ||||
-rw-r--r-- | block/cfq-iosched.c | 12 | ||||
-rw-r--r-- | block/genhd.c | 42 | ||||
-rw-r--r-- | block/partition-generic.c | 48 | ||||
-rw-r--r-- | drivers/block/DAC960.c | 18 | ||||
-rw-r--r-- | drivers/block/sx8.c | 2 | ||||
-rw-r--r-- | fs/block_dev.c | 16 | ||||
-rw-r--r-- | include/linux/genhd.h | 1 | ||||
-rw-r--r-- | include/linux/iocontext.h | 10 | ||||
-rw-r--r-- | include/linux/workqueue.h | 4 | ||||
-rw-r--r-- | kernel/workqueue.c | 7 |
11 files changed, 199 insertions, 96 deletions
diff --git a/block/blk-ioc.c b/block/blk-ioc.c index 8b782a63c297..fb95dd2f889a 100644 --- a/block/blk-ioc.c +++ b/block/blk-ioc.c | |||
@@ -36,11 +36,23 @@ static void icq_free_icq_rcu(struct rcu_head *head) | |||
36 | kmem_cache_free(icq->__rcu_icq_cache, icq); | 36 | kmem_cache_free(icq->__rcu_icq_cache, icq); |
37 | } | 37 | } |
38 | 38 | ||
39 | /* | 39 | /* Exit an icq. Called with both ioc and q locked. */ |
40 | * Exit and free an icq. Called with both ioc and q locked. | ||
41 | */ | ||
42 | static void ioc_exit_icq(struct io_cq *icq) | 40 | static void ioc_exit_icq(struct io_cq *icq) |
43 | { | 41 | { |
42 | struct elevator_type *et = icq->q->elevator->type; | ||
43 | |||
44 | if (icq->flags & ICQ_EXITED) | ||
45 | return; | ||
46 | |||
47 | if (et->ops.elevator_exit_icq_fn) | ||
48 | et->ops.elevator_exit_icq_fn(icq); | ||
49 | |||
50 | icq->flags |= ICQ_EXITED; | ||
51 | } | ||
52 | |||
53 | /* Release an icq. Called with both ioc and q locked. */ | ||
54 | static void ioc_destroy_icq(struct io_cq *icq) | ||
55 | { | ||
44 | struct io_context *ioc = icq->ioc; | 56 | struct io_context *ioc = icq->ioc; |
45 | struct request_queue *q = icq->q; | 57 | struct request_queue *q = icq->q; |
46 | struct elevator_type *et = q->elevator->type; | 58 | struct elevator_type *et = q->elevator->type; |
@@ -60,8 +72,7 @@ static void ioc_exit_icq(struct io_cq *icq) | |||
60 | if (rcu_dereference_raw(ioc->icq_hint) == icq) | 72 | if (rcu_dereference_raw(ioc->icq_hint) == icq) |
61 | rcu_assign_pointer(ioc->icq_hint, NULL); | 73 | rcu_assign_pointer(ioc->icq_hint, NULL); |
62 | 74 | ||
63 | if (et->ops.elevator_exit_icq_fn) | 75 | ioc_exit_icq(icq); |
64 | et->ops.elevator_exit_icq_fn(icq); | ||
65 | 76 | ||
66 | /* | 77 | /* |
67 | * @icq->q might have gone away by the time RCU callback runs | 78 | * @icq->q might have gone away by the time RCU callback runs |
@@ -79,7 +90,6 @@ static void ioc_release_fn(struct work_struct *work) | |||
79 | { | 90 | { |
80 | struct io_context *ioc = container_of(work, struct io_context, | 91 | struct io_context *ioc = container_of(work, struct io_context, |
81 | release_work); | 92 | release_work); |
82 | struct request_queue *last_q = NULL; | ||
83 | unsigned long flags; | 93 | unsigned long flags; |
84 | 94 | ||
85 | /* | 95 | /* |
@@ -93,44 +103,19 @@ static void ioc_release_fn(struct work_struct *work) | |||
93 | while (!hlist_empty(&ioc->icq_list)) { | 103 | while (!hlist_empty(&ioc->icq_list)) { |
94 | struct io_cq *icq = hlist_entry(ioc->icq_list.first, | 104 | struct io_cq *icq = hlist_entry(ioc->icq_list.first, |
95 | struct io_cq, ioc_node); | 105 | struct io_cq, ioc_node); |
96 | struct request_queue *this_q = icq->q; | 106 | struct request_queue *q = icq->q; |
97 | 107 | ||
98 | if (this_q != last_q) { | 108 | if (spin_trylock(q->queue_lock)) { |
99 | /* | 109 | ioc_destroy_icq(icq); |
100 | * Need to switch to @this_q. Once we release | 110 | spin_unlock(q->queue_lock); |
101 | * @ioc->lock, it can go away along with @cic. | 111 | } else { |
102 | * Hold on to it. | 112 | spin_unlock_irqrestore(&ioc->lock, flags); |
103 | */ | 113 | cpu_relax(); |
104 | __blk_get_queue(this_q); | 114 | spin_lock_irqsave_nested(&ioc->lock, flags, 1); |
105 | |||
106 | /* | ||
107 | * blk_put_queue() might sleep thanks to kobject | ||
108 | * idiocy. Always release both locks, put and | ||
109 | * restart. | ||
110 | */ | ||
111 | if (last_q) { | ||
112 | spin_unlock(last_q->queue_lock); | ||
113 | spin_unlock_irqrestore(&ioc->lock, flags); | ||
114 | blk_put_queue(last_q); | ||
115 | } else { | ||
116 | spin_unlock_irqrestore(&ioc->lock, flags); | ||
117 | } | ||
118 | |||
119 | last_q = this_q; | ||
120 | spin_lock_irqsave(this_q->queue_lock, flags); | ||
121 | spin_lock_nested(&ioc->lock, 1); | ||
122 | continue; | ||
123 | } | 115 | } |
124 | ioc_exit_icq(icq); | ||
125 | } | 116 | } |
126 | 117 | ||
127 | if (last_q) { | 118 | spin_unlock_irqrestore(&ioc->lock, flags); |
128 | spin_unlock(last_q->queue_lock); | ||
129 | spin_unlock_irqrestore(&ioc->lock, flags); | ||
130 | blk_put_queue(last_q); | ||
131 | } else { | ||
132 | spin_unlock_irqrestore(&ioc->lock, flags); | ||
133 | } | ||
134 | 119 | ||
135 | kmem_cache_free(iocontext_cachep, ioc); | 120 | kmem_cache_free(iocontext_cachep, ioc); |
136 | } | 121 | } |
@@ -145,6 +130,7 @@ static void ioc_release_fn(struct work_struct *work) | |||
145 | void put_io_context(struct io_context *ioc) | 130 | void put_io_context(struct io_context *ioc) |
146 | { | 131 | { |
147 | unsigned long flags; | 132 | unsigned long flags; |
133 | bool free_ioc = false; | ||
148 | 134 | ||
149 | if (ioc == NULL) | 135 | if (ioc == NULL) |
150 | return; | 136 | return; |
@@ -159,8 +145,13 @@ void put_io_context(struct io_context *ioc) | |||
159 | spin_lock_irqsave(&ioc->lock, flags); | 145 | spin_lock_irqsave(&ioc->lock, flags); |
160 | if (!hlist_empty(&ioc->icq_list)) | 146 | if (!hlist_empty(&ioc->icq_list)) |
161 | schedule_work(&ioc->release_work); | 147 | schedule_work(&ioc->release_work); |
148 | else | ||
149 | free_ioc = true; | ||
162 | spin_unlock_irqrestore(&ioc->lock, flags); | 150 | spin_unlock_irqrestore(&ioc->lock, flags); |
163 | } | 151 | } |
152 | |||
153 | if (free_ioc) | ||
154 | kmem_cache_free(iocontext_cachep, ioc); | ||
164 | } | 155 | } |
165 | EXPORT_SYMBOL(put_io_context); | 156 | EXPORT_SYMBOL(put_io_context); |
166 | 157 | ||
@@ -168,13 +159,41 @@ EXPORT_SYMBOL(put_io_context); | |||
168 | void exit_io_context(struct task_struct *task) | 159 | void exit_io_context(struct task_struct *task) |
169 | { | 160 | { |
170 | struct io_context *ioc; | 161 | struct io_context *ioc; |
162 | struct io_cq *icq; | ||
163 | struct hlist_node *n; | ||
164 | unsigned long flags; | ||
171 | 165 | ||
172 | task_lock(task); | 166 | task_lock(task); |
173 | ioc = task->io_context; | 167 | ioc = task->io_context; |
174 | task->io_context = NULL; | 168 | task->io_context = NULL; |
175 | task_unlock(task); | 169 | task_unlock(task); |
176 | 170 | ||
177 | atomic_dec(&ioc->nr_tasks); | 171 | if (!atomic_dec_and_test(&ioc->nr_tasks)) { |
172 | put_io_context(ioc); | ||
173 | return; | ||
174 | } | ||
175 | |||
176 | /* | ||
177 | * Need ioc lock to walk icq_list and q lock to exit icq. Perform | ||
178 | * reverse double locking. Read comment in ioc_release_fn() for | ||
179 | * explanation on the nested locking annotation. | ||
180 | */ | ||
181 | retry: | ||
182 | spin_lock_irqsave_nested(&ioc->lock, flags, 1); | ||
183 | hlist_for_each_entry(icq, n, &ioc->icq_list, ioc_node) { | ||
184 | if (icq->flags & ICQ_EXITED) | ||
185 | continue; | ||
186 | if (spin_trylock(icq->q->queue_lock)) { | ||
187 | ioc_exit_icq(icq); | ||
188 | spin_unlock(icq->q->queue_lock); | ||
189 | } else { | ||
190 | spin_unlock_irqrestore(&ioc->lock, flags); | ||
191 | cpu_relax(); | ||
192 | goto retry; | ||
193 | } | ||
194 | } | ||
195 | spin_unlock_irqrestore(&ioc->lock, flags); | ||
196 | |||
178 | put_io_context(ioc); | 197 | put_io_context(ioc); |
179 | } | 198 | } |
180 | 199 | ||
@@ -194,7 +213,7 @@ void ioc_clear_queue(struct request_queue *q) | |||
194 | struct io_context *ioc = icq->ioc; | 213 | struct io_context *ioc = icq->ioc; |
195 | 214 | ||
196 | spin_lock(&ioc->lock); | 215 | spin_lock(&ioc->lock); |
197 | ioc_exit_icq(icq); | 216 | ioc_destroy_icq(icq); |
198 | spin_unlock(&ioc->lock); | 217 | spin_unlock(&ioc->lock); |
199 | } | 218 | } |
200 | } | 219 | } |
@@ -363,13 +382,13 @@ struct io_cq *ioc_create_icq(struct request_queue *q, gfp_t gfp_mask) | |||
363 | return icq; | 382 | return icq; |
364 | } | 383 | } |
365 | 384 | ||
366 | void ioc_set_changed(struct io_context *ioc, int which) | 385 | void ioc_set_icq_flags(struct io_context *ioc, unsigned int flags) |
367 | { | 386 | { |
368 | struct io_cq *icq; | 387 | struct io_cq *icq; |
369 | struct hlist_node *n; | 388 | struct hlist_node *n; |
370 | 389 | ||
371 | hlist_for_each_entry(icq, n, &ioc->icq_list, ioc_node) | 390 | hlist_for_each_entry(icq, n, &ioc->icq_list, ioc_node) |
372 | set_bit(which, &icq->changed); | 391 | icq->flags |= flags; |
373 | } | 392 | } |
374 | 393 | ||
375 | /** | 394 | /** |
@@ -387,7 +406,7 @@ void ioc_ioprio_changed(struct io_context *ioc, int ioprio) | |||
387 | 406 | ||
388 | spin_lock_irqsave(&ioc->lock, flags); | 407 | spin_lock_irqsave(&ioc->lock, flags); |
389 | ioc->ioprio = ioprio; | 408 | ioc->ioprio = ioprio; |
390 | ioc_set_changed(ioc, ICQ_IOPRIO_CHANGED); | 409 | ioc_set_icq_flags(ioc, ICQ_IOPRIO_CHANGED); |
391 | spin_unlock_irqrestore(&ioc->lock, flags); | 410 | spin_unlock_irqrestore(&ioc->lock, flags); |
392 | } | 411 | } |
393 | 412 | ||
@@ -404,11 +423,33 @@ void ioc_cgroup_changed(struct io_context *ioc) | |||
404 | unsigned long flags; | 423 | unsigned long flags; |
405 | 424 | ||
406 | spin_lock_irqsave(&ioc->lock, flags); | 425 | spin_lock_irqsave(&ioc->lock, flags); |
407 | ioc_set_changed(ioc, ICQ_CGROUP_CHANGED); | 426 | ioc_set_icq_flags(ioc, ICQ_CGROUP_CHANGED); |
408 | spin_unlock_irqrestore(&ioc->lock, flags); | 427 | spin_unlock_irqrestore(&ioc->lock, flags); |
409 | } | 428 | } |
410 | EXPORT_SYMBOL(ioc_cgroup_changed); | 429 | EXPORT_SYMBOL(ioc_cgroup_changed); |
411 | 430 | ||
431 | /** | ||
432 | * icq_get_changed - fetch and clear icq changed mask | ||
433 | * @icq: icq of interest | ||
434 | * | ||
435 | * Fetch and clear ICQ_*_CHANGED bits from @icq. Grabs and releases | ||
436 | * @icq->ioc->lock. | ||
437 | */ | ||
438 | unsigned icq_get_changed(struct io_cq *icq) | ||
439 | { | ||
440 | unsigned int changed = 0; | ||
441 | unsigned long flags; | ||
442 | |||
443 | if (unlikely(icq->flags & ICQ_CHANGED_MASK)) { | ||
444 | spin_lock_irqsave(&icq->ioc->lock, flags); | ||
445 | changed = icq->flags & ICQ_CHANGED_MASK; | ||
446 | icq->flags &= ~ICQ_CHANGED_MASK; | ||
447 | spin_unlock_irqrestore(&icq->ioc->lock, flags); | ||
448 | } | ||
449 | return changed; | ||
450 | } | ||
451 | EXPORT_SYMBOL(icq_get_changed); | ||
452 | |||
412 | static int __init blk_ioc_init(void) | 453 | static int __init blk_ioc_init(void) |
413 | { | 454 | { |
414 | iocontext_cachep = kmem_cache_create("blkdev_ioc", | 455 | iocontext_cachep = kmem_cache_create("blkdev_ioc", |
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index d0ba50533668..457295253566 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c | |||
@@ -3470,20 +3470,20 @@ cfq_set_request(struct request_queue *q, struct request *rq, gfp_t gfp_mask) | |||
3470 | const int rw = rq_data_dir(rq); | 3470 | const int rw = rq_data_dir(rq); |
3471 | const bool is_sync = rq_is_sync(rq); | 3471 | const bool is_sync = rq_is_sync(rq); |
3472 | struct cfq_queue *cfqq; | 3472 | struct cfq_queue *cfqq; |
3473 | unsigned int changed; | ||
3473 | 3474 | ||
3474 | might_sleep_if(gfp_mask & __GFP_WAIT); | 3475 | might_sleep_if(gfp_mask & __GFP_WAIT); |
3475 | 3476 | ||
3476 | spin_lock_irq(q->queue_lock); | 3477 | spin_lock_irq(q->queue_lock); |
3477 | 3478 | ||
3478 | /* handle changed notifications */ | 3479 | /* handle changed notifications */ |
3479 | if (unlikely(cic->icq.changed)) { | 3480 | changed = icq_get_changed(&cic->icq); |
3480 | if (test_and_clear_bit(ICQ_IOPRIO_CHANGED, &cic->icq.changed)) | 3481 | if (unlikely(changed & ICQ_IOPRIO_CHANGED)) |
3481 | changed_ioprio(cic); | 3482 | changed_ioprio(cic); |
3482 | #ifdef CONFIG_CFQ_GROUP_IOSCHED | 3483 | #ifdef CONFIG_CFQ_GROUP_IOSCHED |
3483 | if (test_and_clear_bit(ICQ_CGROUP_CHANGED, &cic->icq.changed)) | 3484 | if (unlikely(changed & ICQ_CGROUP_CHANGED)) |
3484 | changed_cgroup(cic); | 3485 | changed_cgroup(cic); |
3485 | #endif | 3486 | #endif |
3486 | } | ||
3487 | 3487 | ||
3488 | new_queue: | 3488 | new_queue: |
3489 | cfqq = cic_to_cfqq(cic, is_sync); | 3489 | cfqq = cic_to_cfqq(cic, is_sync); |
diff --git a/block/genhd.c b/block/genhd.c index 23b4f7063322..df9816ede75b 100644 --- a/block/genhd.c +++ b/block/genhd.c | |||
@@ -35,6 +35,7 @@ static DEFINE_IDR(ext_devt_idr); | |||
35 | 35 | ||
36 | static struct device_type disk_type; | 36 | static struct device_type disk_type; |
37 | 37 | ||
38 | static void disk_alloc_events(struct gendisk *disk); | ||
38 | static void disk_add_events(struct gendisk *disk); | 39 | static void disk_add_events(struct gendisk *disk); |
39 | static void disk_del_events(struct gendisk *disk); | 40 | static void disk_del_events(struct gendisk *disk); |
40 | static void disk_release_events(struct gendisk *disk); | 41 | static void disk_release_events(struct gendisk *disk); |
@@ -601,6 +602,8 @@ void add_disk(struct gendisk *disk) | |||
601 | disk->major = MAJOR(devt); | 602 | disk->major = MAJOR(devt); |
602 | disk->first_minor = MINOR(devt); | 603 | disk->first_minor = MINOR(devt); |
603 | 604 | ||
605 | disk_alloc_events(disk); | ||
606 | |||
604 | /* Register BDI before referencing it from bdev */ | 607 | /* Register BDI before referencing it from bdev */ |
605 | bdi = &disk->queue->backing_dev_info; | 608 | bdi = &disk->queue->backing_dev_info; |
606 | bdi_register_dev(bdi, disk_devt(disk)); | 609 | bdi_register_dev(bdi, disk_devt(disk)); |
@@ -1475,9 +1478,9 @@ static void __disk_unblock_events(struct gendisk *disk, bool check_now) | |||
1475 | intv = disk_events_poll_jiffies(disk); | 1478 | intv = disk_events_poll_jiffies(disk); |
1476 | set_timer_slack(&ev->dwork.timer, intv / 4); | 1479 | set_timer_slack(&ev->dwork.timer, intv / 4); |
1477 | if (check_now) | 1480 | if (check_now) |
1478 | queue_delayed_work(system_nrt_wq, &ev->dwork, 0); | 1481 | queue_delayed_work(system_nrt_freezable_wq, &ev->dwork, 0); |
1479 | else if (intv) | 1482 | else if (intv) |
1480 | queue_delayed_work(system_nrt_wq, &ev->dwork, intv); | 1483 | queue_delayed_work(system_nrt_freezable_wq, &ev->dwork, intv); |
1481 | out_unlock: | 1484 | out_unlock: |
1482 | spin_unlock_irqrestore(&ev->lock, flags); | 1485 | spin_unlock_irqrestore(&ev->lock, flags); |
1483 | } | 1486 | } |
@@ -1521,7 +1524,7 @@ void disk_flush_events(struct gendisk *disk, unsigned int mask) | |||
1521 | ev->clearing |= mask; | 1524 | ev->clearing |= mask; |
1522 | if (!ev->block) { | 1525 | if (!ev->block) { |
1523 | cancel_delayed_work(&ev->dwork); | 1526 | cancel_delayed_work(&ev->dwork); |
1524 | queue_delayed_work(system_nrt_wq, &ev->dwork, 0); | 1527 | queue_delayed_work(system_nrt_freezable_wq, &ev->dwork, 0); |
1525 | } | 1528 | } |
1526 | spin_unlock_irq(&ev->lock); | 1529 | spin_unlock_irq(&ev->lock); |
1527 | } | 1530 | } |
@@ -1558,7 +1561,7 @@ unsigned int disk_clear_events(struct gendisk *disk, unsigned int mask) | |||
1558 | 1561 | ||
1559 | /* uncondtionally schedule event check and wait for it to finish */ | 1562 | /* uncondtionally schedule event check and wait for it to finish */ |
1560 | disk_block_events(disk); | 1563 | disk_block_events(disk); |
1561 | queue_delayed_work(system_nrt_wq, &ev->dwork, 0); | 1564 | queue_delayed_work(system_nrt_freezable_wq, &ev->dwork, 0); |
1562 | flush_delayed_work(&ev->dwork); | 1565 | flush_delayed_work(&ev->dwork); |
1563 | __disk_unblock_events(disk, false); | 1566 | __disk_unblock_events(disk, false); |
1564 | 1567 | ||
@@ -1595,7 +1598,7 @@ static void disk_events_workfn(struct work_struct *work) | |||
1595 | 1598 | ||
1596 | intv = disk_events_poll_jiffies(disk); | 1599 | intv = disk_events_poll_jiffies(disk); |
1597 | if (!ev->block && intv) | 1600 | if (!ev->block && intv) |
1598 | queue_delayed_work(system_nrt_wq, &ev->dwork, intv); | 1601 | queue_delayed_work(system_nrt_freezable_wq, &ev->dwork, intv); |
1599 | 1602 | ||
1600 | spin_unlock_irq(&ev->lock); | 1603 | spin_unlock_irq(&ev->lock); |
1601 | 1604 | ||
@@ -1733,9 +1736,9 @@ module_param_cb(events_dfl_poll_msecs, &disk_events_dfl_poll_msecs_param_ops, | |||
1733 | &disk_events_dfl_poll_msecs, 0644); | 1736 | &disk_events_dfl_poll_msecs, 0644); |
1734 | 1737 | ||
1735 | /* | 1738 | /* |
1736 | * disk_{add|del|release}_events - initialize and destroy disk_events. | 1739 | * disk_{alloc|add|del|release}_events - initialize and destroy disk_events. |
1737 | */ | 1740 | */ |
1738 | static void disk_add_events(struct gendisk *disk) | 1741 | static void disk_alloc_events(struct gendisk *disk) |
1739 | { | 1742 | { |
1740 | struct disk_events *ev; | 1743 | struct disk_events *ev; |
1741 | 1744 | ||
@@ -1748,16 +1751,6 @@ static void disk_add_events(struct gendisk *disk) | |||
1748 | return; | 1751 | return; |
1749 | } | 1752 | } |
1750 | 1753 | ||
1751 | if (sysfs_create_files(&disk_to_dev(disk)->kobj, | ||
1752 | disk_events_attrs) < 0) { | ||
1753 | pr_warn("%s: failed to create sysfs files for events\n", | ||
1754 | disk->disk_name); | ||
1755 | kfree(ev); | ||
1756 | return; | ||
1757 | } | ||
1758 | |||
1759 | disk->ev = ev; | ||
1760 | |||
1761 | INIT_LIST_HEAD(&ev->node); | 1754 | INIT_LIST_HEAD(&ev->node); |
1762 | ev->disk = disk; | 1755 | ev->disk = disk; |
1763 | spin_lock_init(&ev->lock); | 1756 | spin_lock_init(&ev->lock); |
@@ -1766,8 +1759,21 @@ static void disk_add_events(struct gendisk *disk) | |||
1766 | ev->poll_msecs = -1; | 1759 | ev->poll_msecs = -1; |
1767 | INIT_DELAYED_WORK(&ev->dwork, disk_events_workfn); | 1760 | INIT_DELAYED_WORK(&ev->dwork, disk_events_workfn); |
1768 | 1761 | ||
1762 | disk->ev = ev; | ||
1763 | } | ||
1764 | |||
1765 | static void disk_add_events(struct gendisk *disk) | ||
1766 | { | ||
1767 | if (!disk->ev) | ||
1768 | return; | ||
1769 | |||
1770 | /* FIXME: error handling */ | ||
1771 | if (sysfs_create_files(&disk_to_dev(disk)->kobj, disk_events_attrs) < 0) | ||
1772 | pr_warn("%s: failed to create sysfs files for events\n", | ||
1773 | disk->disk_name); | ||
1774 | |||
1769 | mutex_lock(&disk_events_mutex); | 1775 | mutex_lock(&disk_events_mutex); |
1770 | list_add_tail(&ev->node, &disk_events); | 1776 | list_add_tail(&disk->ev->node, &disk_events); |
1771 | mutex_unlock(&disk_events_mutex); | 1777 | mutex_unlock(&disk_events_mutex); |
1772 | 1778 | ||
1773 | /* | 1779 | /* |
diff --git a/block/partition-generic.c b/block/partition-generic.c index d06ec1c829c2..6df5d6928a44 100644 --- a/block/partition-generic.c +++ b/block/partition-generic.c | |||
@@ -389,17 +389,11 @@ static bool disk_unlock_native_capacity(struct gendisk *disk) | |||
389 | } | 389 | } |
390 | } | 390 | } |
391 | 391 | ||
392 | int rescan_partitions(struct gendisk *disk, struct block_device *bdev) | 392 | static int drop_partitions(struct gendisk *disk, struct block_device *bdev) |
393 | { | 393 | { |
394 | struct parsed_partitions *state = NULL; | ||
395 | struct disk_part_iter piter; | 394 | struct disk_part_iter piter; |
396 | struct hd_struct *part; | 395 | struct hd_struct *part; |
397 | int p, highest, res; | 396 | int res; |
398 | rescan: | ||
399 | if (state && !IS_ERR(state)) { | ||
400 | kfree(state); | ||
401 | state = NULL; | ||
402 | } | ||
403 | 397 | ||
404 | if (bdev->bd_part_count) | 398 | if (bdev->bd_part_count) |
405 | return -EBUSY; | 399 | return -EBUSY; |
@@ -412,6 +406,24 @@ rescan: | |||
412 | delete_partition(disk, part->partno); | 406 | delete_partition(disk, part->partno); |
413 | disk_part_iter_exit(&piter); | 407 | disk_part_iter_exit(&piter); |
414 | 408 | ||
409 | return 0; | ||
410 | } | ||
411 | |||
412 | int rescan_partitions(struct gendisk *disk, struct block_device *bdev) | ||
413 | { | ||
414 | struct parsed_partitions *state = NULL; | ||
415 | struct hd_struct *part; | ||
416 | int p, highest, res; | ||
417 | rescan: | ||
418 | if (state && !IS_ERR(state)) { | ||
419 | kfree(state); | ||
420 | state = NULL; | ||
421 | } | ||
422 | |||
423 | res = drop_partitions(disk, bdev); | ||
424 | if (res) | ||
425 | return res; | ||
426 | |||
415 | if (disk->fops->revalidate_disk) | 427 | if (disk->fops->revalidate_disk) |
416 | disk->fops->revalidate_disk(disk); | 428 | disk->fops->revalidate_disk(disk); |
417 | check_disk_size_change(disk, bdev); | 429 | check_disk_size_change(disk, bdev); |
@@ -515,6 +527,26 @@ rescan: | |||
515 | return 0; | 527 | return 0; |
516 | } | 528 | } |
517 | 529 | ||
530 | int invalidate_partitions(struct gendisk *disk, struct block_device *bdev) | ||
531 | { | ||
532 | int res; | ||
533 | |||
534 | if (!bdev->bd_invalidated) | ||
535 | return 0; | ||
536 | |||
537 | res = drop_partitions(disk, bdev); | ||
538 | if (res) | ||
539 | return res; | ||
540 | |||
541 | set_capacity(disk, 0); | ||
542 | check_disk_size_change(disk, bdev); | ||
543 | bdev->bd_invalidated = 0; | ||
544 | /* tell userspace that the media / partition table may have changed */ | ||
545 | kobject_uevent(&disk_to_dev(disk)->kobj, KOBJ_CHANGE); | ||
546 | |||
547 | return 0; | ||
548 | } | ||
549 | |||
518 | unsigned char *read_dev_sector(struct block_device *bdev, sector_t n, Sector *p) | 550 | unsigned char *read_dev_sector(struct block_device *bdev, sector_t n, Sector *p) |
519 | { | 551 | { |
520 | struct address_space *mapping = bdev->bd_inode->i_mapping; | 552 | struct address_space *mapping = bdev->bd_inode->i_mapping; |
diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c index e086fbbbe853..8db9089127c5 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c | |||
@@ -1177,7 +1177,8 @@ static bool DAC960_V1_EnableMemoryMailboxInterface(DAC960_Controller_T | |||
1177 | int TimeoutCounter; | 1177 | int TimeoutCounter; |
1178 | int i; | 1178 | int i; |
1179 | 1179 | ||
1180 | 1180 | memset(&CommandMailbox, 0, sizeof(DAC960_V1_CommandMailbox_T)); | |
1181 | |||
1181 | if (pci_set_dma_mask(Controller->PCIDevice, DMA_BIT_MASK(32))) | 1182 | if (pci_set_dma_mask(Controller->PCIDevice, DMA_BIT_MASK(32))) |
1182 | return DAC960_Failure(Controller, "DMA mask out of range"); | 1183 | return DAC960_Failure(Controller, "DMA mask out of range"); |
1183 | Controller->BounceBufferLimit = DMA_BIT_MASK(32); | 1184 | Controller->BounceBufferLimit = DMA_BIT_MASK(32); |
@@ -4627,7 +4628,8 @@ static void DAC960_V2_ProcessCompletedCommand(DAC960_Command_T *Command) | |||
4627 | DAC960_Controller_T *Controller = Command->Controller; | 4628 | DAC960_Controller_T *Controller = Command->Controller; |
4628 | DAC960_CommandType_T CommandType = Command->CommandType; | 4629 | DAC960_CommandType_T CommandType = Command->CommandType; |
4629 | DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox; | 4630 | DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox; |
4630 | DAC960_V2_IOCTL_Opcode_T CommandOpcode = CommandMailbox->Common.IOCTL_Opcode; | 4631 | DAC960_V2_IOCTL_Opcode_T IOCTLOpcode = CommandMailbox->Common.IOCTL_Opcode; |
4632 | DAC960_V2_CommandOpcode_T CommandOpcode = CommandMailbox->SCSI_10.CommandOpcode; | ||
4631 | DAC960_V2_CommandStatus_T CommandStatus = Command->V2.CommandStatus; | 4633 | DAC960_V2_CommandStatus_T CommandStatus = Command->V2.CommandStatus; |
4632 | 4634 | ||
4633 | if (CommandType == DAC960_ReadCommand || | 4635 | if (CommandType == DAC960_ReadCommand || |
@@ -4699,7 +4701,7 @@ static void DAC960_V2_ProcessCompletedCommand(DAC960_Command_T *Command) | |||
4699 | { | 4701 | { |
4700 | if (Controller->ShutdownMonitoringTimer) | 4702 | if (Controller->ShutdownMonitoringTimer) |
4701 | return; | 4703 | return; |
4702 | if (CommandOpcode == DAC960_V2_GetControllerInfo) | 4704 | if (IOCTLOpcode == DAC960_V2_GetControllerInfo) |
4703 | { | 4705 | { |
4704 | DAC960_V2_ControllerInfo_T *NewControllerInfo = | 4706 | DAC960_V2_ControllerInfo_T *NewControllerInfo = |
4705 | Controller->V2.NewControllerInformation; | 4707 | Controller->V2.NewControllerInformation; |
@@ -4719,14 +4721,14 @@ static void DAC960_V2_ProcessCompletedCommand(DAC960_Command_T *Command) | |||
4719 | memcpy(ControllerInfo, NewControllerInfo, | 4721 | memcpy(ControllerInfo, NewControllerInfo, |
4720 | sizeof(DAC960_V2_ControllerInfo_T)); | 4722 | sizeof(DAC960_V2_ControllerInfo_T)); |
4721 | } | 4723 | } |
4722 | else if (CommandOpcode == DAC960_V2_GetEvent) | 4724 | else if (IOCTLOpcode == DAC960_V2_GetEvent) |
4723 | { | 4725 | { |
4724 | if (CommandStatus == DAC960_V2_NormalCompletion) { | 4726 | if (CommandStatus == DAC960_V2_NormalCompletion) { |
4725 | DAC960_V2_ReportEvent(Controller, Controller->V2.Event); | 4727 | DAC960_V2_ReportEvent(Controller, Controller->V2.Event); |
4726 | } | 4728 | } |
4727 | Controller->V2.NextEventSequenceNumber++; | 4729 | Controller->V2.NextEventSequenceNumber++; |
4728 | } | 4730 | } |
4729 | else if (CommandOpcode == DAC960_V2_GetPhysicalDeviceInfoValid && | 4731 | else if (IOCTLOpcode == DAC960_V2_GetPhysicalDeviceInfoValid && |
4730 | CommandStatus == DAC960_V2_NormalCompletion) | 4732 | CommandStatus == DAC960_V2_NormalCompletion) |
4731 | { | 4733 | { |
4732 | DAC960_V2_PhysicalDeviceInfo_T *NewPhysicalDeviceInfo = | 4734 | DAC960_V2_PhysicalDeviceInfo_T *NewPhysicalDeviceInfo = |
@@ -4915,7 +4917,7 @@ static void DAC960_V2_ProcessCompletedCommand(DAC960_Command_T *Command) | |||
4915 | NewPhysicalDeviceInfo->LogicalUnit++; | 4917 | NewPhysicalDeviceInfo->LogicalUnit++; |
4916 | Controller->V2.PhysicalDeviceIndex++; | 4918 | Controller->V2.PhysicalDeviceIndex++; |
4917 | } | 4919 | } |
4918 | else if (CommandOpcode == DAC960_V2_GetPhysicalDeviceInfoValid) | 4920 | else if (IOCTLOpcode == DAC960_V2_GetPhysicalDeviceInfoValid) |
4919 | { | 4921 | { |
4920 | unsigned int DeviceIndex; | 4922 | unsigned int DeviceIndex; |
4921 | for (DeviceIndex = Controller->V2.PhysicalDeviceIndex; | 4923 | for (DeviceIndex = Controller->V2.PhysicalDeviceIndex; |
@@ -4938,7 +4940,7 @@ static void DAC960_V2_ProcessCompletedCommand(DAC960_Command_T *Command) | |||
4938 | } | 4940 | } |
4939 | Controller->V2.NeedPhysicalDeviceInformation = false; | 4941 | Controller->V2.NeedPhysicalDeviceInformation = false; |
4940 | } | 4942 | } |
4941 | else if (CommandOpcode == DAC960_V2_GetLogicalDeviceInfoValid && | 4943 | else if (IOCTLOpcode == DAC960_V2_GetLogicalDeviceInfoValid && |
4942 | CommandStatus == DAC960_V2_NormalCompletion) | 4944 | CommandStatus == DAC960_V2_NormalCompletion) |
4943 | { | 4945 | { |
4944 | DAC960_V2_LogicalDeviceInfo_T *NewLogicalDeviceInfo = | 4946 | DAC960_V2_LogicalDeviceInfo_T *NewLogicalDeviceInfo = |
@@ -5065,7 +5067,7 @@ static void DAC960_V2_ProcessCompletedCommand(DAC960_Command_T *Command) | |||
5065 | [LogicalDeviceNumber] = true; | 5067 | [LogicalDeviceNumber] = true; |
5066 | NewLogicalDeviceInfo->LogicalDeviceNumber++; | 5068 | NewLogicalDeviceInfo->LogicalDeviceNumber++; |
5067 | } | 5069 | } |
5068 | else if (CommandOpcode == DAC960_V2_GetLogicalDeviceInfoValid) | 5070 | else if (IOCTLOpcode == DAC960_V2_GetLogicalDeviceInfoValid) |
5069 | { | 5071 | { |
5070 | int LogicalDriveNumber; | 5072 | int LogicalDriveNumber; |
5071 | for (LogicalDriveNumber = 0; | 5073 | for (LogicalDriveNumber = 0; |
diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c index e7472f567c9d..3fb6ab4c8b4e 100644 --- a/drivers/block/sx8.c +++ b/drivers/block/sx8.c | |||
@@ -1120,7 +1120,7 @@ static inline void carm_handle_resp(struct carm_host *host, | |||
1120 | break; | 1120 | break; |
1121 | case MISC_GET_FW_VER: { | 1121 | case MISC_GET_FW_VER: { |
1122 | struct carm_fw_ver *ver = (struct carm_fw_ver *) | 1122 | struct carm_fw_ver *ver = (struct carm_fw_ver *) |
1123 | mem + sizeof(struct carm_msg_get_fw_ver); | 1123 | (mem + sizeof(struct carm_msg_get_fw_ver)); |
1124 | if (!error) { | 1124 | if (!error) { |
1125 | host->fw_ver = le32_to_cpu(ver->version); | 1125 | host->fw_ver = le32_to_cpu(ver->version); |
1126 | host->flags |= (ver->features & FL_FW_VER_MASK); | 1126 | host->flags |= (ver->features & FL_FW_VER_MASK); |
diff --git a/fs/block_dev.c b/fs/block_dev.c index 0e575d1304b4..5e9f198f7712 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
@@ -1183,8 +1183,12 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) | |||
1183 | * The latter is necessary to prevent ghost | 1183 | * The latter is necessary to prevent ghost |
1184 | * partitions on a removed medium. | 1184 | * partitions on a removed medium. |
1185 | */ | 1185 | */ |
1186 | if (bdev->bd_invalidated && (!ret || ret == -ENOMEDIUM)) | 1186 | if (bdev->bd_invalidated) { |
1187 | rescan_partitions(disk, bdev); | 1187 | if (!ret) |
1188 | rescan_partitions(disk, bdev); | ||
1189 | else if (ret == -ENOMEDIUM) | ||
1190 | invalidate_partitions(disk, bdev); | ||
1191 | } | ||
1188 | if (ret) | 1192 | if (ret) |
1189 | goto out_clear; | 1193 | goto out_clear; |
1190 | } else { | 1194 | } else { |
@@ -1214,8 +1218,12 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) | |||
1214 | if (bdev->bd_disk->fops->open) | 1218 | if (bdev->bd_disk->fops->open) |
1215 | ret = bdev->bd_disk->fops->open(bdev, mode); | 1219 | ret = bdev->bd_disk->fops->open(bdev, mode); |
1216 | /* the same as first opener case, read comment there */ | 1220 | /* the same as first opener case, read comment there */ |
1217 | if (bdev->bd_invalidated && (!ret || ret == -ENOMEDIUM)) | 1221 | if (bdev->bd_invalidated) { |
1218 | rescan_partitions(bdev->bd_disk, bdev); | 1222 | if (!ret) |
1223 | rescan_partitions(bdev->bd_disk, bdev); | ||
1224 | else if (ret == -ENOMEDIUM) | ||
1225 | invalidate_partitions(bdev->bd_disk, bdev); | ||
1226 | } | ||
1219 | if (ret) | 1227 | if (ret) |
1220 | goto out_unlock_bdev; | 1228 | goto out_unlock_bdev; |
1221 | } | 1229 | } |
diff --git a/include/linux/genhd.h b/include/linux/genhd.h index fe23ee768589..e61d3192448e 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h | |||
@@ -596,6 +596,7 @@ extern char *disk_name (struct gendisk *hd, int partno, char *buf); | |||
596 | 596 | ||
597 | extern int disk_expand_part_tbl(struct gendisk *disk, int target); | 597 | extern int disk_expand_part_tbl(struct gendisk *disk, int target); |
598 | extern int rescan_partitions(struct gendisk *disk, struct block_device *bdev); | 598 | extern int rescan_partitions(struct gendisk *disk, struct block_device *bdev); |
599 | extern int invalidate_partitions(struct gendisk *disk, struct block_device *bdev); | ||
599 | extern struct hd_struct * __must_check add_partition(struct gendisk *disk, | 600 | extern struct hd_struct * __must_check add_partition(struct gendisk *disk, |
600 | int partno, sector_t start, | 601 | int partno, sector_t start, |
601 | sector_t len, int flags, | 602 | sector_t len, int flags, |
diff --git a/include/linux/iocontext.h b/include/linux/iocontext.h index 119773eebe31..1a3018063034 100644 --- a/include/linux/iocontext.h +++ b/include/linux/iocontext.h | |||
@@ -6,8 +6,11 @@ | |||
6 | #include <linux/workqueue.h> | 6 | #include <linux/workqueue.h> |
7 | 7 | ||
8 | enum { | 8 | enum { |
9 | ICQ_IOPRIO_CHANGED, | 9 | ICQ_IOPRIO_CHANGED = 1 << 0, |
10 | ICQ_CGROUP_CHANGED, | 10 | ICQ_CGROUP_CHANGED = 1 << 1, |
11 | ICQ_EXITED = 1 << 2, | ||
12 | |||
13 | ICQ_CHANGED_MASK = ICQ_IOPRIO_CHANGED | ICQ_CGROUP_CHANGED, | ||
11 | }; | 14 | }; |
12 | 15 | ||
13 | /* | 16 | /* |
@@ -88,7 +91,7 @@ struct io_cq { | |||
88 | struct rcu_head __rcu_head; | 91 | struct rcu_head __rcu_head; |
89 | }; | 92 | }; |
90 | 93 | ||
91 | unsigned long changed; | 94 | unsigned int flags; |
92 | }; | 95 | }; |
93 | 96 | ||
94 | /* | 97 | /* |
@@ -139,6 +142,7 @@ struct io_context *get_task_io_context(struct task_struct *task, | |||
139 | gfp_t gfp_flags, int node); | 142 | gfp_t gfp_flags, int node); |
140 | void ioc_ioprio_changed(struct io_context *ioc, int ioprio); | 143 | void ioc_ioprio_changed(struct io_context *ioc, int ioprio); |
141 | void ioc_cgroup_changed(struct io_context *ioc); | 144 | void ioc_cgroup_changed(struct io_context *ioc); |
145 | unsigned int icq_get_changed(struct io_cq *icq); | ||
142 | #else | 146 | #else |
143 | struct io_context; | 147 | struct io_context; |
144 | static inline void put_io_context(struct io_context *ioc) { } | 148 | static inline void put_io_context(struct io_context *ioc) { } |
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index eb8b9f15f2e0..af155450cabb 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h | |||
@@ -289,12 +289,16 @@ enum { | |||
289 | * | 289 | * |
290 | * system_freezable_wq is equivalent to system_wq except that it's | 290 | * system_freezable_wq is equivalent to system_wq except that it's |
291 | * freezable. | 291 | * freezable. |
292 | * | ||
293 | * system_nrt_freezable_wq is equivalent to system_nrt_wq except that | ||
294 | * it's freezable. | ||
292 | */ | 295 | */ |
293 | extern struct workqueue_struct *system_wq; | 296 | extern struct workqueue_struct *system_wq; |
294 | extern struct workqueue_struct *system_long_wq; | 297 | extern struct workqueue_struct *system_long_wq; |
295 | extern struct workqueue_struct *system_nrt_wq; | 298 | extern struct workqueue_struct *system_nrt_wq; |
296 | extern struct workqueue_struct *system_unbound_wq; | 299 | extern struct workqueue_struct *system_unbound_wq; |
297 | extern struct workqueue_struct *system_freezable_wq; | 300 | extern struct workqueue_struct *system_freezable_wq; |
301 | extern struct workqueue_struct *system_nrt_freezable_wq; | ||
298 | 302 | ||
299 | extern struct workqueue_struct * | 303 | extern struct workqueue_struct * |
300 | __alloc_workqueue_key(const char *fmt, unsigned int flags, int max_active, | 304 | __alloc_workqueue_key(const char *fmt, unsigned int flags, int max_active, |
diff --git a/kernel/workqueue.c b/kernel/workqueue.c index bec7b5b53e03..f2c5638bb5ab 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c | |||
@@ -253,11 +253,13 @@ struct workqueue_struct *system_long_wq __read_mostly; | |||
253 | struct workqueue_struct *system_nrt_wq __read_mostly; | 253 | struct workqueue_struct *system_nrt_wq __read_mostly; |
254 | struct workqueue_struct *system_unbound_wq __read_mostly; | 254 | struct workqueue_struct *system_unbound_wq __read_mostly; |
255 | struct workqueue_struct *system_freezable_wq __read_mostly; | 255 | struct workqueue_struct *system_freezable_wq __read_mostly; |
256 | struct workqueue_struct *system_nrt_freezable_wq __read_mostly; | ||
256 | EXPORT_SYMBOL_GPL(system_wq); | 257 | EXPORT_SYMBOL_GPL(system_wq); |
257 | EXPORT_SYMBOL_GPL(system_long_wq); | 258 | EXPORT_SYMBOL_GPL(system_long_wq); |
258 | EXPORT_SYMBOL_GPL(system_nrt_wq); | 259 | EXPORT_SYMBOL_GPL(system_nrt_wq); |
259 | EXPORT_SYMBOL_GPL(system_unbound_wq); | 260 | EXPORT_SYMBOL_GPL(system_unbound_wq); |
260 | EXPORT_SYMBOL_GPL(system_freezable_wq); | 261 | EXPORT_SYMBOL_GPL(system_freezable_wq); |
262 | EXPORT_SYMBOL_GPL(system_nrt_freezable_wq); | ||
261 | 263 | ||
262 | #define CREATE_TRACE_POINTS | 264 | #define CREATE_TRACE_POINTS |
263 | #include <trace/events/workqueue.h> | 265 | #include <trace/events/workqueue.h> |
@@ -3833,8 +3835,11 @@ static int __init init_workqueues(void) | |||
3833 | WQ_UNBOUND_MAX_ACTIVE); | 3835 | WQ_UNBOUND_MAX_ACTIVE); |
3834 | system_freezable_wq = alloc_workqueue("events_freezable", | 3836 | system_freezable_wq = alloc_workqueue("events_freezable", |
3835 | WQ_FREEZABLE, 0); | 3837 | WQ_FREEZABLE, 0); |
3838 | system_nrt_freezable_wq = alloc_workqueue("events_nrt_freezable", | ||
3839 | WQ_NON_REENTRANT | WQ_FREEZABLE, 0); | ||
3836 | BUG_ON(!system_wq || !system_long_wq || !system_nrt_wq || | 3840 | BUG_ON(!system_wq || !system_long_wq || !system_nrt_wq || |
3837 | !system_unbound_wq || !system_freezable_wq); | 3841 | !system_unbound_wq || !system_freezable_wq || |
3842 | !system_nrt_freezable_wq); | ||
3838 | return 0; | 3843 | return 0; |
3839 | } | 3844 | } |
3840 | early_initcall(init_workqueues); | 3845 | early_initcall(init_workqueues); |