File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -1136,8 +1136,13 @@ static void virtio_ccw_int_handler(struct ccw_device *cdev,
11361136 vcdev -> err = - EIO ;
11371137 }
11381138 virtio_ccw_check_activity (vcdev , activity );
1139- /* Interrupts are disabled here */
1139+ #ifdef CONFIG_VIRTIO_HARDEN_NOTIFICATION
1140+ /*
1141+ * Paired with virtio_ccw_synchronize_cbs() and interrupts are
1142+ * disabled here.
1143+ */
11401144 read_lock (& vcdev -> irq_lock );
1145+ #endif
11411146 for_each_set_bit (i , indicators (vcdev ),
11421147 sizeof (* indicators (vcdev )) * BITS_PER_BYTE ) {
11431148 /* The bit clear must happen before the vring kick. */
@@ -1146,7 +1151,9 @@ static void virtio_ccw_int_handler(struct ccw_device *cdev,
11461151 vq = virtio_ccw_vq_by_ind (vcdev , i );
11471152 vring_interrupt (0 , vq );
11481153 }
1154+ #ifdef CONFIG_VIRTIO_HARDEN_NOTIFICATION
11491155 read_unlock (& vcdev -> irq_lock );
1156+ #endif
11501157 if (test_bit (0 , indicators2 (vcdev ))) {
11511158 virtio_config_changed (& vcdev -> vdev );
11521159 clear_bit (0 , indicators2 (vcdev ));
Original file line number Diff line number Diff line change @@ -29,6 +29,19 @@ menuconfig VIRTIO_MENU
2929
3030if VIRTIO_MENU
3131
32+ config VIRTIO_HARDEN_NOTIFICATION
33+ bool "Harden virtio notification"
34+ help
35+ Enable this to harden the device notifications and suppress
36+ those that happen at a time where notifications are illegal.
37+
38+ Experimental: Note that several drivers still have bugs that
39+ may cause crashes or hangs when correct handling of
40+ notifications is enforced; depending on the subset of
41+ drivers and devices you use, this may or may not work.
42+
43+ If unsure, say N.
44+
3245config VIRTIO_PCI
3346 tristate "PCI driver for virtio devices"
3447 depends on PCI
Original file line number Diff line number Diff line change @@ -219,6 +219,7 @@ static int virtio_features_ok(struct virtio_device *dev)
219219 * */
220220void virtio_reset_device (struct virtio_device * dev )
221221{
222+ #ifdef CONFIG_VIRTIO_HARDEN_NOTIFICATION
222223 /*
223224 * The below virtio_synchronize_cbs() guarantees that any
224225 * interrupt for this line arriving after
@@ -227,6 +228,7 @@ void virtio_reset_device(struct virtio_device *dev)
227228 */
228229 virtio_break_device (dev );
229230 virtio_synchronize_cbs (dev );
231+ #endif
230232
231233 dev -> config -> reset (dev );
232234}
Original file line number Diff line number Diff line change @@ -1708,7 +1708,11 @@ static struct virtqueue *vring_create_virtqueue_packed(
17081708 vq -> we_own_ring = true;
17091709 vq -> notify = notify ;
17101710 vq -> weak_barriers = weak_barriers ;
1711+ #ifdef CONFIG_VIRTIO_HARDEN_NOTIFICATION
17111712 vq -> broken = true;
1713+ #else
1714+ vq -> broken = false;
1715+ #endif
17121716 vq -> last_used_idx = 0 | (1 << VRING_PACKED_EVENT_F_WRAP_CTR );
17131717 vq -> event_triggered = false;
17141718 vq -> num_added = 0 ;
@@ -2154,9 +2158,13 @@ irqreturn_t vring_interrupt(int irq, void *_vq)
21542158 }
21552159
21562160 if (unlikely (vq -> broken )) {
2161+ #ifdef CONFIG_VIRTIO_HARDEN_NOTIFICATION
21572162 dev_warn_once (& vq -> vq .vdev -> dev ,
21582163 "virtio vring IRQ raised before DRIVER_OK" );
21592164 return IRQ_NONE ;
2165+ #else
2166+ return IRQ_HANDLED ;
2167+ #endif
21602168 }
21612169
21622170 /* Just a hint for performance: so it's ok that this can be racy! */
@@ -2199,7 +2207,11 @@ struct virtqueue *__vring_new_virtqueue(unsigned int index,
21992207 vq -> we_own_ring = false;
22002208 vq -> notify = notify ;
22012209 vq -> weak_barriers = weak_barriers ;
2210+ #ifdef CONFIG_VIRTIO_HARDEN_NOTIFICATION
22022211 vq -> broken = true;
2212+ #else
2213+ vq -> broken = false;
2214+ #endif
22032215 vq -> last_used_idx = 0 ;
22042216 vq -> event_triggered = false;
22052217 vq -> num_added = 0 ;
Original file line number Diff line number Diff line change @@ -257,13 +257,15 @@ void virtio_device_ready(struct virtio_device *dev)
257257
258258 WARN_ON (status & VIRTIO_CONFIG_S_DRIVER_OK );
259259
260+ #ifdef CONFIG_VIRTIO_HARDEN_NOTIFICATION
260261 /*
261262 * The virtio_synchronize_cbs() makes sure vring_interrupt()
262263 * will see the driver specific setup if it sees vq->broken
263264 * as false (even if the notifications come before DRIVER_OK).
264265 */
265266 virtio_synchronize_cbs (dev );
266267 __virtio_unbreak_device (dev );
268+ #endif
267269 /*
268270 * The transport should ensure the visibility of vq->broken
269271 * before setting DRIVER_OK. See the comments for the transport
You can’t perform that action at this time.
0 commit comments