diff options
author | Wei Wang <wei.w.wang@intel.com> | 2019-01-07 02:01:04 -0500 |
---|---|---|
committer | Michael S. Tsirkin <mst@redhat.com> | 2019-01-14 20:15:20 -0500 |
commit | bf4dc0b2beebfd9338df7c0bcf473b356f67cf66 (patch) | |
tree | 2f7d09c5a40626a7cac01a49dee42b225d3405ef | |
parent | a229989d975eb926076307c1f2f5e4c6111768e7 (diff) |
virtio-balloon: tweak config_changed implementation
virtio-ccw has deadlock issues with reading the config space inside the
interrupt context, so we tweak the virtballoon_changed implementation
by moving the config read operations into the related workqueue contexts.
The config_read_bitmap is used as a flag to the workqueue callbacks
about the related config fields that need to be read.
The cmd_id_received is also renamed to cmd_id_received_cache, and
the value should be obtained via virtio_balloon_cmd_id_received.
Reported-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Wei Wang <wei.w.wang@intel.com>
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
Reviewed-by: Halil Pasic <pasic@linux.ibm.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Cc: stable@vger.kernel.org
Fixes: 86a559787e6f ("virtio-balloon: VIRTIO_BALLOON_F_FREE_PAGE_HINT")
Tested-by: Christian Borntraeger <borntraeger@de.ibm.com>
-rw-r--r-- | drivers/virtio/virtio_balloon.c | 98 |
1 files changed, 65 insertions, 33 deletions
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c index 728ecd1eea30..fb12fe205f86 100644 --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c | |||
@@ -61,6 +61,10 @@ enum virtio_balloon_vq { | |||
61 | VIRTIO_BALLOON_VQ_MAX | 61 | VIRTIO_BALLOON_VQ_MAX |
62 | }; | 62 | }; |
63 | 63 | ||
64 | enum virtio_balloon_config_read { | ||
65 | VIRTIO_BALLOON_CONFIG_READ_CMD_ID = 0, | ||
66 | }; | ||
67 | |||
64 | struct virtio_balloon { | 68 | struct virtio_balloon { |
65 | struct virtio_device *vdev; | 69 | struct virtio_device *vdev; |
66 | struct virtqueue *inflate_vq, *deflate_vq, *stats_vq, *free_page_vq; | 70 | struct virtqueue *inflate_vq, *deflate_vq, *stats_vq, *free_page_vq; |
@@ -77,14 +81,20 @@ struct virtio_balloon { | |||
77 | /* Prevent updating balloon when it is being canceled. */ | 81 | /* Prevent updating balloon when it is being canceled. */ |
78 | spinlock_t stop_update_lock; | 82 | spinlock_t stop_update_lock; |
79 | bool stop_update; | 83 | bool stop_update; |
84 | /* Bitmap to indicate if reading the related config fields are needed */ | ||
85 | unsigned long config_read_bitmap; | ||
80 | 86 | ||
81 | /* The list of allocated free pages, waiting to be given back to mm */ | 87 | /* The list of allocated free pages, waiting to be given back to mm */ |
82 | struct list_head free_page_list; | 88 | struct list_head free_page_list; |
83 | spinlock_t free_page_list_lock; | 89 | spinlock_t free_page_list_lock; |
84 | /* The number of free page blocks on the above list */ | 90 | /* The number of free page blocks on the above list */ |
85 | unsigned long num_free_page_blocks; | 91 | unsigned long num_free_page_blocks; |
86 | /* The cmd id received from host */ | 92 | /* |
87 | u32 cmd_id_received; | 93 | * The cmd id received from host. |
94 | * Read it via virtio_balloon_cmd_id_received to get the latest value | ||
95 | * sent from host. | ||
96 | */ | ||
97 | u32 cmd_id_received_cache; | ||
88 | /* The cmd id that is actively in use */ | 98 | /* The cmd id that is actively in use */ |
89 | __virtio32 cmd_id_active; | 99 | __virtio32 cmd_id_active; |
90 | /* Buffer to store the stop sign */ | 100 | /* Buffer to store the stop sign */ |
@@ -390,37 +400,31 @@ static unsigned long return_free_pages_to_mm(struct virtio_balloon *vb, | |||
390 | return num_returned; | 400 | return num_returned; |
391 | } | 401 | } |
392 | 402 | ||
403 | static void virtio_balloon_queue_free_page_work(struct virtio_balloon *vb) | ||
404 | { | ||
405 | if (!virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT)) | ||
406 | return; | ||
407 | |||
408 | /* No need to queue the work if the bit was already set. */ | ||
409 | if (test_and_set_bit(VIRTIO_BALLOON_CONFIG_READ_CMD_ID, | ||
410 | &vb->config_read_bitmap)) | ||
411 | return; | ||
412 | |||
413 | queue_work(vb->balloon_wq, &vb->report_free_page_work); | ||
414 | } | ||
415 | |||
393 | static void virtballoon_changed(struct virtio_device *vdev) | 416 | static void virtballoon_changed(struct virtio_device *vdev) |
394 | { | 417 | { |
395 | struct virtio_balloon *vb = vdev->priv; | 418 | struct virtio_balloon *vb = vdev->priv; |
396 | unsigned long flags; | 419 | unsigned long flags; |
397 | s64 diff = towards_target(vb); | ||
398 | |||
399 | if (diff) { | ||
400 | spin_lock_irqsave(&vb->stop_update_lock, flags); | ||
401 | if (!vb->stop_update) | ||
402 | queue_work(system_freezable_wq, | ||
403 | &vb->update_balloon_size_work); | ||
404 | spin_unlock_irqrestore(&vb->stop_update_lock, flags); | ||
405 | } | ||
406 | 420 | ||
407 | if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT)) { | 421 | spin_lock_irqsave(&vb->stop_update_lock, flags); |
408 | virtio_cread(vdev, struct virtio_balloon_config, | 422 | if (!vb->stop_update) { |
409 | free_page_report_cmd_id, &vb->cmd_id_received); | 423 | queue_work(system_freezable_wq, |
410 | if (vb->cmd_id_received == VIRTIO_BALLOON_CMD_ID_DONE) { | 424 | &vb->update_balloon_size_work); |
411 | /* Pass ULONG_MAX to give back all the free pages */ | 425 | virtio_balloon_queue_free_page_work(vb); |
412 | return_free_pages_to_mm(vb, ULONG_MAX); | ||
413 | } else if (vb->cmd_id_received != VIRTIO_BALLOON_CMD_ID_STOP && | ||
414 | vb->cmd_id_received != | ||
415 | virtio32_to_cpu(vdev, vb->cmd_id_active)) { | ||
416 | spin_lock_irqsave(&vb->stop_update_lock, flags); | ||
417 | if (!vb->stop_update) { | ||
418 | queue_work(vb->balloon_wq, | ||
419 | &vb->report_free_page_work); | ||
420 | } | ||
421 | spin_unlock_irqrestore(&vb->stop_update_lock, flags); | ||
422 | } | ||
423 | } | 426 | } |
427 | spin_unlock_irqrestore(&vb->stop_update_lock, flags); | ||
424 | } | 428 | } |
425 | 429 | ||
426 | static void update_balloon_size(struct virtio_balloon *vb) | 430 | static void update_balloon_size(struct virtio_balloon *vb) |
@@ -527,6 +531,17 @@ static int init_vqs(struct virtio_balloon *vb) | |||
527 | return 0; | 531 | return 0; |
528 | } | 532 | } |
529 | 533 | ||
534 | static u32 virtio_balloon_cmd_id_received(struct virtio_balloon *vb) | ||
535 | { | ||
536 | if (test_and_clear_bit(VIRTIO_BALLOON_CONFIG_READ_CMD_ID, | ||
537 | &vb->config_read_bitmap)) | ||
538 | virtio_cread(vb->vdev, struct virtio_balloon_config, | ||
539 | free_page_report_cmd_id, | ||
540 | &vb->cmd_id_received_cache); | ||
541 | |||
542 | return vb->cmd_id_received_cache; | ||
543 | } | ||
544 | |||
530 | static int send_cmd_id_start(struct virtio_balloon *vb) | 545 | static int send_cmd_id_start(struct virtio_balloon *vb) |
531 | { | 546 | { |
532 | struct scatterlist sg; | 547 | struct scatterlist sg; |
@@ -537,7 +552,8 @@ static int send_cmd_id_start(struct virtio_balloon *vb) | |||
537 | while (virtqueue_get_buf(vq, &unused)) | 552 | while (virtqueue_get_buf(vq, &unused)) |
538 | ; | 553 | ; |
539 | 554 | ||
540 | vb->cmd_id_active = cpu_to_virtio32(vb->vdev, vb->cmd_id_received); | 555 | vb->cmd_id_active = virtio32_to_cpu(vb->vdev, |
556 | virtio_balloon_cmd_id_received(vb)); | ||
541 | sg_init_one(&sg, &vb->cmd_id_active, sizeof(vb->cmd_id_active)); | 557 | sg_init_one(&sg, &vb->cmd_id_active, sizeof(vb->cmd_id_active)); |
542 | err = virtqueue_add_outbuf(vq, &sg, 1, &vb->cmd_id_active, GFP_KERNEL); | 558 | err = virtqueue_add_outbuf(vq, &sg, 1, &vb->cmd_id_active, GFP_KERNEL); |
543 | if (!err) | 559 | if (!err) |
@@ -620,7 +636,8 @@ static int send_free_pages(struct virtio_balloon *vb) | |||
620 | * stop the reporting. | 636 | * stop the reporting. |
621 | */ | 637 | */ |
622 | cmd_id_active = virtio32_to_cpu(vb->vdev, vb->cmd_id_active); | 638 | cmd_id_active = virtio32_to_cpu(vb->vdev, vb->cmd_id_active); |
623 | if (cmd_id_active != vb->cmd_id_received) | 639 | if (unlikely(cmd_id_active != |
640 | virtio_balloon_cmd_id_received(vb))) | ||
624 | break; | 641 | break; |
625 | 642 | ||
626 | /* | 643 | /* |
@@ -637,11 +654,9 @@ static int send_free_pages(struct virtio_balloon *vb) | |||
637 | return 0; | 654 | return 0; |
638 | } | 655 | } |
639 | 656 | ||
640 | static void report_free_page_func(struct work_struct *work) | 657 | static void virtio_balloon_report_free_page(struct virtio_balloon *vb) |
641 | { | 658 | { |
642 | int err; | 659 | int err; |
643 | struct virtio_balloon *vb = container_of(work, struct virtio_balloon, | ||
644 | report_free_page_work); | ||
645 | struct device *dev = &vb->vdev->dev; | 660 | struct device *dev = &vb->vdev->dev; |
646 | 661 | ||
647 | /* Start by sending the received cmd id to host with an outbuf. */ | 662 | /* Start by sending the received cmd id to host with an outbuf. */ |
@@ -659,6 +674,23 @@ static void report_free_page_func(struct work_struct *work) | |||
659 | dev_err(dev, "Failed to send a stop id, err = %d\n", err); | 674 | dev_err(dev, "Failed to send a stop id, err = %d\n", err); |
660 | } | 675 | } |
661 | 676 | ||
677 | static void report_free_page_func(struct work_struct *work) | ||
678 | { | ||
679 | struct virtio_balloon *vb = container_of(work, struct virtio_balloon, | ||
680 | report_free_page_work); | ||
681 | u32 cmd_id_received; | ||
682 | |||
683 | cmd_id_received = virtio_balloon_cmd_id_received(vb); | ||
684 | if (cmd_id_received == VIRTIO_BALLOON_CMD_ID_DONE) { | ||
685 | /* Pass ULONG_MAX to give back all the free pages */ | ||
686 | return_free_pages_to_mm(vb, ULONG_MAX); | ||
687 | } else if (cmd_id_received != VIRTIO_BALLOON_CMD_ID_STOP && | ||
688 | cmd_id_received != | ||
689 | virtio32_to_cpu(vb->vdev, vb->cmd_id_active)) { | ||
690 | virtio_balloon_report_free_page(vb); | ||
691 | } | ||
692 | } | ||
693 | |||
662 | #ifdef CONFIG_BALLOON_COMPACTION | 694 | #ifdef CONFIG_BALLOON_COMPACTION |
663 | /* | 695 | /* |
664 | * virtballoon_migratepage - perform the balloon page migration on behalf of | 696 | * virtballoon_migratepage - perform the balloon page migration on behalf of |
@@ -885,7 +917,7 @@ static int virtballoon_probe(struct virtio_device *vdev) | |||
885 | goto out_del_vqs; | 917 | goto out_del_vqs; |
886 | } | 918 | } |
887 | INIT_WORK(&vb->report_free_page_work, report_free_page_func); | 919 | INIT_WORK(&vb->report_free_page_work, report_free_page_func); |
888 | vb->cmd_id_received = VIRTIO_BALLOON_CMD_ID_STOP; | 920 | vb->cmd_id_received_cache = VIRTIO_BALLOON_CMD_ID_STOP; |
889 | vb->cmd_id_active = cpu_to_virtio32(vb->vdev, | 921 | vb->cmd_id_active = cpu_to_virtio32(vb->vdev, |
890 | VIRTIO_BALLOON_CMD_ID_STOP); | 922 | VIRTIO_BALLOON_CMD_ID_STOP); |
891 | vb->cmd_id_stop = cpu_to_virtio32(vb->vdev, | 923 | vb->cmd_id_stop = cpu_to_virtio32(vb->vdev, |