From: Amit Shah <hidden> Date: 2011-12-06 19:49:21
Hi,
These patches add support for S4 to virtio (pci) and all drivers.
For each driver, all vqs are removed before hibernation, and then
re-created after restore. Some driver-specific uninit and init work
is also done in the freeze and restore functions.
All the drivers in testing work fine:
* virtio-blk is used for the only disk in the VM, IO works fine before
and after. 'dd if=/dev/zero of=/tmp/bigfile bs=1024 count=200000'
across S4 gives same sha1sum for the file in the guest as well as
one that's created without invoking S4.
* virtio-console: port IO keeps working fine before and after.
* If a port is waiting for data from the host (blocking read(2)
call), this works fine in both the cases: host-side connection is
available or unavailable after resume. In case the host-side
connection isn't available, the blocking call is terminated. If
it is available, the call continues to remain in blocked state
till further data arrives.
* virtio-net: ping remains active across S4.
* virtio-balloon: Works fine before and after. Forgets the ballooned
value across S4 (see details in commit log). Maintains ballooned
value on failed freeze.
All of these tests are run in parallel.
I have some more tests lined up on similar lines above. I'll reply
here if something breaks.
Please review and apply if appropriate,
v4:
- Disable / enable napi across S4 (Michael S. Tsirkin)
- Balloon: lots of improvements (I had neglected this driver thinking
it was a simple one, but this one needed the most thought! Check
the commit log for patch 12 for details.)
- Net, Blk: Reset device as the first operation on freeze
v3:
- Reset vqs before deleting them (Sasha Levin)
- Flush block queue before freeze (Rusty)
- Detach netdev before freeze (Michael S. Tsirkin)
v2:
- fix checkpatch errors/warnings
Amit Shah (12):
virtio: pci: switch to new PM API
virtio: pci: add PM notification handlers for restore, freeze, thaw,
poweroff
virtio: console: Move out vq and vq buf removal into separate
functions
virtio: console: Add freeze and restore handlers to support S4
virtio: blk: Move out vq initialization to separate function
virtio: blk: Add freeze, restore handlers to support S4
virtio: net: Move out vq initialization into separate function
virtio: net: Move out vq and vq buf removal into separate function
virtio: net: Add freeze, restore handlers to support S4
virtio: balloon: ensure thread exists before stopping it
virtio: balloon: Move out vq initialization into separate function
virtio: balloon: Add freeze, restore handlers to support S4
drivers/block/virtio_blk.c | 57 +++++++++++++++--
drivers/char/virtio_console.c | 126 +++++++++++++++++++++++++++++--------
drivers/net/virtio_net.c | 102 ++++++++++++++++++++++--------
drivers/virtio/virtio_balloon.c | 131 +++++++++++++++++++++++++++++++++------
drivers/virtio/virtio_pci.c | 101 +++++++++++++++++++++++++++++-
include/linux/virtio.h | 5 ++
6 files changed, 439 insertions(+), 83 deletions(-)
--
1.7.7.3
From: Amit Shah <hidden> Date: 2011-12-06 19:49:25
The older PM API doesn't have a way to get notifications on hibernate
events. Switch to the newer one that gives us those notifications.
Signed-off-by: Amit Shah <redacted>
---
drivers/virtio/virtio_pci.c | 16 ++++++++++++----
1 files changed, 12 insertions(+), 4 deletions(-)
From: Amit Shah <hidden> Date: 2011-12-06 19:49:33
Handle thaw, restore and freeze notifications from the PM core. Expose
these to individual virtio drivers that can quiesce and resume vq
operations. For drivers not implementing the thaw() method, use the
restore method instead.
These functions also save device-specific data so that the device can be
put in pre-suspend state after resume, and disable and enable the PCI
device in the freeze and resume functions, respectively.
Signed-off-by: Amit Shah <redacted>
---
drivers/virtio/virtio_pci.c | 85 +++++++++++++++++++++++++++++++++++++++++++
include/linux/virtio.h | 5 +++
2 files changed, 90 insertions(+), 0 deletions(-)
@@ -55,6 +55,10 @@ struct virtio_pci_deviceunsignedmsix_vectors;/* Vectors allocated, excluding per-vq vectors if any */unsignedmsix_used_vectors;++/* Status saved during hibernate/restore */+u8saved_status;+/* Whether we have vector per vq */boolper_vq_vectors;};
@@ -726,9 +730,90 @@ static int virtio_pci_resume(struct device *dev)return0;}+staticintvirtio_pci_freeze(structdevice*dev)+{+structpci_dev*pci_dev=to_pci_dev(dev);+structvirtio_pci_device*vp_dev=pci_get_drvdata(pci_dev);+structvirtio_driver*drv;+intret;++drv=container_of(vp_dev->vdev.dev.driver,+structvirtio_driver,driver);++ret=0;+vp_dev->saved_status=vp_get_status(&vp_dev->vdev);+if(drv&&drv->freeze)+ret=drv->freeze(&vp_dev->vdev);++if(!ret)+pci_disable_device(pci_dev);+returnret;+}++staticintrestore_common(structdevice*dev)+{+structpci_dev*pci_dev=to_pci_dev(dev);+structvirtio_pci_device*vp_dev=pci_get_drvdata(pci_dev);+intret;++ret=pci_enable_device(pci_dev);+if(ret)+returnret;+pci_set_master(pci_dev);+vp_set_status(&vp_dev->vdev,vp_dev->saved_status);+vp_finalize_features(&vp_dev->vdev);++returnret;+}++staticintvirtio_pci_restore(structdevice*dev)+{+structpci_dev*pci_dev=to_pci_dev(dev);+structvirtio_pci_device*vp_dev=pci_get_drvdata(pci_dev);+structvirtio_driver*drv;+intret;++drv=container_of(vp_dev->vdev.dev.driver,+structvirtio_driver,driver);++ret=restore_common(dev);+if(!ret&&drv&&drv->restore)+ret=drv->restore(&vp_dev->vdev);++returnret;+}++staticintvirtio_pci_thaw(structdevice*dev)+{+structpci_dev*pci_dev=to_pci_dev(dev);+structvirtio_pci_device*vp_dev=pci_get_drvdata(pci_dev);+structvirtio_driver*drv;+intret;++ret=restore_common(dev);+if(ret)+returnret;++drv=container_of(vp_dev->vdev.dev.driver,+structvirtio_driver,driver);+if(!drv)+returnret;++if(drv->thaw)+ret=drv->thaw(&vp_dev->vdev);+elseif(drv->restore)+ret=drv->restore(&vp_dev->vdev);++returnret;+}+staticconststructdev_pm_opsvirtio_pci_pm_ops={.suspend=virtio_pci_suspend,.resume=virtio_pci_resume,+.freeze=virtio_pci_freeze,+.thaw=virtio_pci_thaw,+.restore=virtio_pci_restore,+.poweroff=virtio_pci_suspend,};#endif
From: Amit Shah <hidden> Date: 2011-12-06 19:49:41
This common code will be shared with the PM freeze function.
Signed-off-by: Amit Shah <redacted>
---
drivers/char/virtio_console.c | 68 ++++++++++++++++++++++++-----------------
1 files changed, 40 insertions(+), 28 deletions(-)
@@ -1271,6 +1271,20 @@ static void remove_port(struct kref *kref)kfree(port);}+staticvoidremove_port_data(structport*port)+{+structport_buffer*buf;++/* Remove unused data this port might have received. */+discard_port_data(port);++reclaim_consumed_buffers(port);++/* Remove buffers we queued up for the Host to send us data in. */+while((buf=virtqueue_detach_unused_buf(port->in_vq)))+free_buf(buf);+}+/**Portgotunplugged.Removeportfromportdev'slistanddropthe*krefreference.Ifnouserspacehasthisportopened,itwill
@@ -1300,14 +1312,7 @@ static void unplug_port(struct port *port)hvc_remove(port->cons.hvc);}-/* Remove unused data this port might have received. */-discard_port_data(port);--reclaim_consumed_buffers(port);--/* Remove buffers we queued up for the Host to send us data in. */-while((buf=virtqueue_detach_unused_buf(port->in_vq)))-free_buf(buf);+remove_port_data(port);/**Weshouldjustassumethedeviceitselfhasgoneoff--
From: Amit Shah <hidden> Date: 2011-12-06 19:49:44
Remove all vqs and associated buffers in the freeze callback which
prepares us to go into hibernation state. On restore, re-create all the
vqs and populate the input vqs with buffers to get to the pre-hibernate
state.
Note: Any outstanding unconsumed buffers are discarded; which means
there's a possibility of data loss in case the host or the guest didn't
consume any data already present in the vqs. This can be addressed in a
later patch series, perhaps in virtio common code.
Signed-off-by: Amit Shah <redacted>
---
drivers/char/virtio_console.c | 58 +++++++++++++++++++++++++++++++++++++++++
1 files changed, 58 insertions(+), 0 deletions(-)
@@ -1844,6 +1844,60 @@ static unsigned int features[] = {VIRTIO_CONSOLE_F_MULTIPORT,};+#ifdef CONFIG_PM+staticintvirtcons_freeze(structvirtio_device*vdev)+{+structports_device*portdev;+structport*port;++portdev=vdev->priv;++vdev->config->reset(vdev);++cancel_work_sync(&portdev->control_work);+remove_controlq_data(portdev);++list_for_each_entry(port,&portdev->ports,list){+/*+*We'llaskthehostlaterifthenewinvocationhas+*theportopenedorclosed.+*/+port->host_connected=false;+remove_port_data(port);+}+remove_vqs(portdev);++return0;+}++staticintvirtcons_restore(structvirtio_device*vdev)+{+structports_device*portdev;+structport*port;+intret;++portdev=vdev->priv;++ret=init_vqs(portdev);+if(ret)+returnret;++if(use_multiport(portdev))+fill_queue(portdev->c_ivq,&portdev->cvq_lock);++list_for_each_entry(port,&portdev->ports,list){+port->in_vq=portdev->in_vqs[port->id];+port->out_vq=portdev->out_vqs[port->id];++fill_queue(port->in_vq,&port->inbuf_lock);++/* Get port open/close status on the host */+send_control_msg(port,VIRTIO_CONSOLE_PORT_READY,1);+}+return0;+}+#endif+staticstructvirtio_drivervirtio_console={.feature_table=features,.feature_table_size=ARRAY_SIZE(features),
From: Amit Shah <hidden> Date: 2011-12-06 19:49:48
The probe and PM restore functions will share this code.
Signed-off-by: Amit Shah <redacted>
---
drivers/block/virtio_blk.c | 19 ++++++++++++++-----
1 files changed, 14 insertions(+), 5 deletions(-)
@@ -349,6 +349,18 @@ static void virtblk_config_changed(struct virtio_device *vdev)queue_work(virtblk_wq,&vblk->config_work);}+staticintinit_vq(structvirtio_blk*vblk)+{+interr=0;++/* We expect one virtqueue, for output. */+vblk->vq=virtio_find_single_vq(vblk->vdev,blk_done,"requests");+if(IS_ERR(vblk->vq))+err=PTR_ERR(vblk->vq);++returnerr;+}+staticint__devinitvirtblk_probe(structvirtio_device*vdev){structvirtio_blk*vblk;
@@ -390,12 +402,9 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)sg_init_table(vblk->sg,vblk->sg_elems);INIT_WORK(&vblk->config_work,virtblk_config_changed_work);-/* We expect one virtqueue, for output. */-vblk->vq=virtio_find_single_vq(vdev,blk_done,"requests");-if(IS_ERR(vblk->vq)){-err=PTR_ERR(vblk->vq);+err=init_vq(vblk);+if(err)gotoout_free_vblk;-}vblk->pool=mempool_create_kmalloc_pool(1,sizeof(structvirtblk_req));if(!vblk->pool){
From: Amit Shah <hidden> Date: 2011-12-06 19:49:52
Delete the vq and flush any pending requests from the block queue on the
freeze callback to prepare for hibernation.
Re-create the vq in the restore callback to resume normal function.
Signed-off-by: Amit Shah <redacted>
---
drivers/block/virtio_blk.c | 38 ++++++++++++++++++++++++++++++++++++++
1 files changed, 38 insertions(+), 0 deletions(-)
From: Amit Shah <hidden> Date: 2011-12-06 19:49:55
The probe and PM restore functions will share this code.
Signed-off-by: Amit Shah <redacted>
---
drivers/net/virtio_net.c | 47 +++++++++++++++++++++++++++------------------
1 files changed, 28 insertions(+), 19 deletions(-)
@@ -954,15 +954,38 @@ static void virtnet_config_changed(struct virtio_device *vdev)virtnet_update_status(vi);}+staticintinit_vqs(structvirtnet_info*vi)+{+structvirtqueue*vqs[3];+vq_callback_t*callbacks[]={skb_recv_done,skb_xmit_done,NULL};+constchar*names[]={"input","output","control"};+intnvqs,err;++/* We expect two virtqueues, receive then send,+*andoptionallycontrol.*/+nvqs=virtio_has_feature(vi->vdev,VIRTIO_NET_F_CTRL_VQ)?3:2;++err=vi->vdev->config->find_vqs(vi->vdev,nvqs,vqs,callbacks,names);+if(err)+returnerr;++vi->rvq=vqs[0];+vi->svq=vqs[1];++if(virtio_has_feature(vi->vdev,VIRTIO_NET_F_CTRL_VQ)){+vi->cvq=vqs[2];++if(virtio_has_feature(vi->vdev,VIRTIO_NET_F_CTRL_VLAN))+vi->dev->features|=NETIF_F_HW_VLAN_FILTER;+}+return0;+}+staticintvirtnet_probe(structvirtio_device*vdev){interr;structnet_device*dev;structvirtnet_info*vi;-structvirtqueue*vqs[3];-vq_callback_t*callbacks[]={skb_recv_done,skb_xmit_done,NULL};-constchar*names[]={"input","output","control"};-intnvqs;/* Allocate ourselves a network device with room for our info */dev=alloc_etherdev(sizeof(structvirtnet_info));
@@ -1034,24 +1057,10 @@ static int virtnet_probe(struct virtio_device *vdev)if(virtio_has_feature(vdev,VIRTIO_NET_F_MRG_RXBUF))vi->mergeable_rx_bufs=true;-/* We expect two virtqueues, receive then send,-*andoptionallycontrol.*/-nvqs=virtio_has_feature(vi->vdev,VIRTIO_NET_F_CTRL_VQ)?3:2;--err=vdev->config->find_vqs(vdev,nvqs,vqs,callbacks,names);+err=init_vqs(vi);if(err)gotofree_stats;-vi->rvq=vqs[0];-vi->svq=vqs[1];--if(virtio_has_feature(vi->vdev,VIRTIO_NET_F_CTRL_VQ)){-vi->cvq=vqs[2];--if(virtio_has_feature(vi->vdev,VIRTIO_NET_F_CTRL_VLAN))-dev->features|=NETIF_F_HW_VLAN_FILTER;-}-err=register_netdev(dev);if(err){pr_debug("virtio_net: registering device failed\n");
From: Amit Shah <hidden> Date: 2011-12-06 19:49:59
The remove and PM freeze functions will share this code.
Signed-off-by: Amit Shah <redacted>
---
drivers/net/virtio_net.c | 19 ++++++++++++-------
1 files changed, 12 insertions(+), 7 deletions(-)
@@ -1123,24 +1123,29 @@ static void free_unused_bufs(struct virtnet_info *vi)BUG_ON(vi->num!=0);}-staticvoid__devexitvirtnet_remove(structvirtio_device*vdev)+staticvoidremove_vq_common(structvirtnet_info*vi){-structvirtnet_info*vi=vdev->priv;-/* Stop all the virtqueues. */-vdev->config->reset(vdev);-+vi->vdev->config->reset(vi->vdev);-unregister_netdev(vi->dev);cancel_delayed_work_sync(&vi->refill);/* Free unused buffers in both send and recv, if any. */free_unused_bufs(vi);-vdev->config->del_vqs(vi->vdev);+vi->vdev->config->del_vqs(vi->vdev);while(vi->pages)__free_pages(get_a_page(vi,GFP_KERNEL),0);+}++staticvoid__devexitvirtnet_remove(structvirtio_device*vdev)+{+structvirtnet_info*vi=vdev->priv;++unregister_netdev(vi->dev);++remove_vq_common(vi);free_percpu(vi->stats);free_netdev(vi->dev);
From: Amit Shah <hidden> Date: 2011-12-06 19:50:05
The vballoon thread could have exited earlier and not re-started.
Ensure we don't try to stop a non-existent thread.
This can happen if the balloon driver goes into S4 state and the thread
exits (this code lands in the next patch). If, however, on restore, the
vqs fail to initialise, the vballoon thread will not be re-created.
Upon a subsequent module removal in that state, we will end up
dereferencing an invalid pointer without this patch.
---
drivers/virtio/virtio_balloon.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
@@ -338,7 +338,9 @@ static void __devexit virtballoon_remove(struct virtio_device *vdev){structvirtio_balloon*vb=vdev->priv;-kthread_stop(vb->thread);+/* Thread may not have started on restore after a suspend */+if(vb->thread)+kthread_stop(vb->thread);/* There might be pages left in the balloon: free them. */while(vb->num_pages)
From: Amit Shah <hidden> Date: 2011-12-06 19:50:08
Remove all the vqs, disable napi and detach from the netdev on
hibernation.
Re-create vqs after restoring from a hibernated image, re-enable napi
and re-attach the netdev. This keeps networking working across
hibernation.
Signed-off-by: Amit Shah <redacted>
---
drivers/net/virtio_net.c | 36 ++++++++++++++++++++++++++++++++++++
1 files changed, 36 insertions(+), 0 deletions(-)
From: Amit Shah <hidden> Date: 2011-12-06 19:50:18
Handling balloon hibernate / restore is tricky. If the balloon was
inflated before going into the hibernation state, upon resume, the host
will not have any memory of that. Any pages that were passed on to the
host earlier would most likely be invalid, and the host will have to
re-balloon to the previous value to get in the pre-hibernate state.
So the only sane thing for the guest to do here is to discard all the
pages that were put in the balloon. When to discard the pages is the
next question.
One solution is to deflate the balloon just before writing the image to
the disk (in the freeze() PM callback). However, asking for pages from
the host just to discard them immediately after seems wasteful of
resources. Hence, it makes sense to do this by just fudging our
counters soon after wakeup. This means we don't deflate the balloon
before sleep, and also don't put unnecessary pressure on the host.
This also helps in the thaw case: if the freeze fails for whatever
reason, the balloon should continue to remain in the inflated state.
This was tested by issuing 'swapoff -a' and trying to go into the S4
state. That fails, and the balloon stays inflated, as expected. Both
the host and the guest are happy.
Now to not race with a host issuing ballooning requests while we are in
the process of freezing, we just exit from the vballoon kthread when the
processes are asked to freeze. Upon thaw and restore, we re-start the
thread.
Finally, in the restore() callback, we empty the list of pages that were
previously given off to the host, add the appropriate number of pages to
the totalram_pages counter, reset the num_pages counter to 0, and
all is fine.
As a last step, delete the vqs on the freeze callback to prepare for
hibernation, and re-create them in the restore and thaw callbacks to
resume normal operation.
Signed-off-by: Amit Shah <redacted>
---
drivers/virtio/virtio_balloon.c | 79 ++++++++++++++++++++++++++++++++++++++-
1 files changed, 78 insertions(+), 1 deletions(-)
@@ -258,7 +258,13 @@ static int balloon(void *_vballoon)while(!kthread_should_stop()){s64diff;-try_to_freeze();+/*+*Onsuspend,wewanttoexitthisthread.Wewill+*startanewthreadonresume.+*/+if(freezing(current))+break;+wait_event_interruptible(vb->config_change,(diff=towards_target(vb))!=0||vb->need_stats_update
@@ -365,6 +371,72 @@ static void __devexit virtballoon_remove(struct virtio_device *vdev)kfree(vb);}+#ifdef CONFIG_PM+staticintvirtballoon_freeze(structvirtio_device*vdev)+{+/* Ensure we don't get any more requests from the host */+vdev->config->reset(vdev);++/*+*ThekthreadisalreadygoneasaresultofthePMcode+*issuingafreezerequest.+*/++vdev->config->del_vqs(vdev);+return0;+}++staticintrestore_common(structvirtio_device*vdev)+{+structvirtio_balloon*vb=vdev->priv;+interr;++/*+*Ifinit_vqsbelowfails,asubsequentmoduleremoval+*shouldn'tcauseustodereferenceinvalidpointers!+*/+vb->thread=NULL;++err=init_vqs(vdev->priv);+if(err)+returnerr;++vb->thread=kthread_run(balloon,vb,"vballoon");+if(IS_ERR(vb->thread)){+err=PTR_ERR(vb->thread);+vb->thread=NULL;+}+returnerr;+}++staticintvirtballoon_thaw(structvirtio_device*vdev)+{+returnrestore_common(vdev);+}++staticintvirtballoon_restore(structvirtio_device*vdev)+{+structvirtio_balloon*vb=vdev->priv;+structpage*page,*page2;++/* We're starting from a clean slate */+vb->num_pages=0;++/*+*Ifarequestwasn'tcompleteatthetimeoffreezing,this+*couldhavebeenset.+*/+vb->need_stats_update=0;++/* We don't have these pages in the balloon anymore! */+list_for_each_entry_safe(page,page2,&vb->pages,lru){+list_del(&page->lru);+totalram_pages++;+}+returnrestore_common(vdev);+}+#endif+staticunsignedintfeatures[]={VIRTIO_BALLOON_F_MUST_TELL_HOST,VIRTIO_BALLOON_F_STATS_VQ,
From: Amit Shah <hidden> Date: 2011-12-06 19:50:44
The probe and PM restore functions will share this code.
Signed-off-by: Amit Shah <redacted>
---
drivers/virtio/virtio_balloon.c | 48 ++++++++++++++++++++++++--------------
1 files changed, 30 insertions(+), 18 deletions(-)
@@ -275,32 +275,21 @@ static int balloon(void *_vballoon)return0;}-staticintvirtballoon_probe(structvirtio_device*vdev)+staticintinit_vqs(structvirtio_balloon*vb){-structvirtio_balloon*vb;structvirtqueue*vqs[3];vq_callback_t*callbacks[]={balloon_ack,balloon_ack,stats_request};constchar*names[]={"inflate","deflate","stats"};interr,nvqs;-vdev->priv=vb=kmalloc(sizeof(*vb),GFP_KERNEL);-if(!vb){-err=-ENOMEM;-gotoout;-}--INIT_LIST_HEAD(&vb->pages);-vb->num_pages=0;-init_waitqueue_head(&vb->config_change);-vb->vdev=vdev;-vb->need_stats_update=0;--/* We expect two virtqueues: inflate and deflate,-*andoptionallystat.*/+/*+*Weexpecttwovirtqueues:inflateanddeflate,and+*optionallystat.+*/nvqs=virtio_has_feature(vb->vdev,VIRTIO_BALLOON_F_STATS_VQ)?3:2;-err=vdev->config->find_vqs(vdev,nvqs,vqs,callbacks,names);+err=vb->vdev->config->find_vqs(vb->vdev,nvqs,vqs,callbacks,names);if(err)-gotoout_free_vb;+returnerr;vb->inflate_vq=vqs[0];vb->deflate_vq=vqs[1];
@@ -317,6 +306,29 @@ static int virtballoon_probe(struct virtio_device *vdev)BUG();virtqueue_kick(vb->stats_vq);}+return0;+}++staticintvirtballoon_probe(structvirtio_device*vdev)+{+structvirtio_balloon*vb;+interr;++vdev->priv=vb=kmalloc(sizeof(*vb),GFP_KERNEL);+if(!vb){+err=-ENOMEM;+gotoout;+}++INIT_LIST_HEAD(&vb->pages);+vb->num_pages=0;+init_waitqueue_head(&vb->config_change);+vb->vdev=vdev;+vb->need_stats_update=0;++err=init_vqs(vb);+if(err)+gotoout_free_vb;vb->thread=kthread_run(balloon,vb,"vballoon");if(IS_ERR(vb->thread)){
From: Rafael J. Wysocki <hidden> Date: 2011-12-06 22:09:40
Hi,
On Tuesday, December 06, 2011, Amit Shah wrote:
quoted hunk
The older PM API doesn't have a way to get notifications on hibernate
events. Switch to the newer one that gives us those notifications.
Signed-off-by: Amit Shah <redacted>
---
drivers/virtio/virtio_pci.c | 16 ++++++++++++----
1 files changed, 12 insertions(+), 4 deletions(-)
You seem to have forgotten about hibernation callbacks. Please use
one the macros defined in include/linux/pm.h if you want to use the same
callback routines for hibernation.
From: Amit Shah <hidden> Date: 2011-12-07 03:57:16
Hi Rafael,
On (Tue) 06 Dec 2011 [23:12:36], Rafael J. Wysocki wrote:
Hi,
On Tuesday, December 06, 2011, Amit Shah wrote:
quoted
The older PM API doesn't have a way to get notifications on hibernate
events. Switch to the newer one that gives us those notifications.
Signed-off-by: Amit Shah <redacted>
---
drivers/virtio/virtio_pci.c | 16 ++++++++++++----
1 files changed, 12 insertions(+), 4 deletions(-)
From: Amit Shah <hidden> Date: 2011-12-07 04:50:58
On (Wed) 07 Dec 2011 [01:18:50], Amit Shah wrote:
[snip]
Now to not race with a host issuing ballooning requests while we are in
the process of freezing, we just exit from the vballoon kthread when the
processes are asked to freeze. Upon thaw and restore, we re-start the
thread.
Actually this isn't necessary. I over-zealously killed the thread
when it's not really necessary: the thread is frozen before calling
the freeze() callback and is thawed only after the restore() or thaw()
callbacks are done, so we're exactly in the same state with or without
keeping the kthread around (just that the PID of the kthread will
change). So I'll back out this change for the next revision.
Amit
From: Rafael J. Wysocki <hidden> Date: 2011-12-07 09:45:29
On Wednesday, December 07, 2011, Amit Shah wrote:
Hi Rafael,
On (Tue) 06 Dec 2011 [23:12:36], Rafael J. Wysocki wrote:
quoted
Hi,
On Tuesday, December 06, 2011, Amit Shah wrote:
quoted
The older PM API doesn't have a way to get notifications on hibernate
events. Switch to the newer one that gives us those notifications.
Signed-off-by: Amit Shah <redacted>
---
drivers/virtio/virtio_pci.c | 16 ++++++++++++----
1 files changed, 12 insertions(+), 4 deletions(-)
From: Amit Shah <hidden> Date: 2011-12-07 09:52:42
On (Wed) 07 Dec 2011 [10:48:24], Rafael J. Wysocki wrote:
On Wednesday, December 07, 2011, Amit Shah wrote:
quoted
Hi Rafael,
On (Tue) 06 Dec 2011 [23:12:36], Rafael J. Wysocki wrote:
quoted
Hi,
On Tuesday, December 06, 2011, Amit Shah wrote:
quoted
The older PM API doesn't have a way to get notifications on hibernate
events. Switch to the newer one that gives us those notifications.
Signed-off-by: Amit Shah <redacted>
---
drivers/virtio/virtio_pci.c | 16 ++++++++++++----
1 files changed, 12 insertions(+), 4 deletions(-)
From: Rafael J. Wysocki <hidden> Date: 2011-12-07 10:13:36
On Wednesday, December 07, 2011, Amit Shah wrote:
On (Wed) 07 Dec 2011 [10:48:24], Rafael J. Wysocki wrote:
quoted
On Wednesday, December 07, 2011, Amit Shah wrote:
quoted
Hi Rafael,
On (Tue) 06 Dec 2011 [23:12:36], Rafael J. Wysocki wrote:
quoted
Hi,
On Tuesday, December 06, 2011, Amit Shah wrote:
quoted
The older PM API doesn't have a way to get notifications on hibernate
events. Switch to the newer one that gives us those notifications.
Signed-off-by: Amit Shah <redacted>
---
drivers/virtio/virtio_pci.c | 16 ++++++++++++----
1 files changed, 12 insertions(+), 4 deletions(-)
From: "Michael S. Tsirkin" <mst@redhat.com> Date: 2011-12-07 10:33:13
On Wed, Dec 07, 2011 at 01:18:50AM +0530, Amit Shah wrote:
Now to not race with a host issuing ballooning requests while we are in
the process of freezing, we just exit from the vballoon kthread when the
processes are asked to freeze. Upon thaw and restore, we re-start the
thread.
@@ -258,7 +258,13 @@ static int balloon(void *_vballoon)while(!kthread_should_stop()){s64diff;-try_to_freeze();+/*+*Onsuspend,wewanttoexitthisthread.Wewill+*startanewthreadonresume.+*/+if(freezing(current))+break;+wait_event_interruptible(vb->config_change,(diff=towards_target(vb))!=0||vb->need_stats_update
...
Note: this relies on kthreads being frozen before devices.
Looking at kernel/power/hibernate.c this is the case,
but I think we should add a comment to note this.
Also Cc linux-pm crowd in case I got it wrong.
---
Resending due to corrupted headers. Sorry about the noise.
--
MST
From: "Michael S. Tsirkin" <mst@redhat.com> Date: 2011-12-07 10:35:23
On Wed, Dec 07, 2011 at 01:18:44AM +0530, Amit Shah wrote:
quoted hunk
Delete the vq and flush any pending requests from the block queue on the
freeze callback to prepare for hibernation.
Re-create the vq in the restore callback to resume normal function.
Signed-off-by: Amit Shah <redacted>
---
drivers/block/virtio_blk.c | 38 ++++++++++++++++++++++++++++++++++++++
1 files changed, 38 insertions(+), 0 deletions(-)
@@ -568,6 +568,40 @@ static void __devexit virtblk_remove(struct virtio_device *vdev)ida_simple_remove(&vd_index_ida,index);}+#ifdef CONFIG_PM+staticintvirtblk_freeze(structvirtio_device*vdev)+{+structvirtio_blk*vblk=vdev->priv;++/* Ensure we don't receive any more interrupts */+vdev->config->reset(vdev);++flush_work(&vblk->config_work);
It bothers me that config work can be running
after reset here. If it does, it will not get sane
values from reading config.
Also, can there be stuff in the reqs list?
If yes is this a problem?
Thinking about it, looks like there's a bug in
virtblk_remove: if we get a config change after
flush_work we schedule another work.
That's a problem for sure as structure is removed.
From: Amit Shah <hidden> Date: 2011-12-07 10:39:58
On (Wed) 07 Dec 2011 [12:34:48], Michael S. Tsirkin wrote:
On Wed, Dec 07, 2011 at 01:18:50AM +0530, Amit Shah wrote:
quoted
Now to not race with a host issuing ballooning requests while we are in
the process of freezing, we just exit from the vballoon kthread when the
processes are asked to freeze. Upon thaw and restore, we re-start the
thread.
@@ -258,7 +258,13 @@ static int balloon(void *_vballoon)while(!kthread_should_stop()){s64diff;-try_to_freeze();+/*+*Onsuspend,wewanttoexitthisthread.Wewill+*startanewthreadonresume.+*/+if(freezing(current))+break;+wait_event_interruptible(vb->config_change,(diff=towards_target(vb))!=0||vb->need_stats_update
...
Note: this relies on kthreads being frozen before devices.
Looking at kernel/power/hibernate.c this is the case,
but I think we should add a comment to note this.
Yes, it does. And for that reason, I mentioned that stopping the
thread doesn't buy us anything; I'll revert this change in the next
submission.
From: "Michael S. Tsirkin" <mst@redhat.com> Date: 2011-12-07 10:41:40
On Wed, Dec 07, 2011 at 01:18:42AM +0530, Amit Shah wrote:
quoted hunk
Remove all vqs and associated buffers in the freeze callback which
prepares us to go into hibernation state. On restore, re-create all the
vqs and populate the input vqs with buffers to get to the pre-hibernate
state.
Note: Any outstanding unconsumed buffers are discarded; which means
there's a possibility of data loss in case the host or the guest didn't
consume any data already present in the vqs. This can be addressed in a
later patch series, perhaps in virtio common code.
Signed-off-by: Amit Shah <redacted>
---
drivers/char/virtio_console.c | 58 +++++++++++++++++++++++++++++++++++++++++
1 files changed, 58 insertions(+), 0 deletions(-)
So here, cancel_work_sync might still be running.
If it does run, might it try to access the device
config? Could not determine this quickly, if yes it's a problem.
quoted hunk
+
+ cancel_work_sync(&portdev->control_work);
+ remove_controlq_data(portdev);
+
+ list_for_each_entry(port, &portdev->ports, list) {
+ /*
+ * We'll ask the host later if the new invocation has
+ * the port opened or closed.
+ */
+ port->host_connected = false;
+ remove_port_data(port);
+ }
+ remove_vqs(portdev);
+
+ return 0;
+}
+
+static int virtcons_restore(struct virtio_device *vdev)
+{
+ struct ports_device *portdev;
+ struct port *port;
+ int ret;
+
+ portdev = vdev->priv;
+
+ ret = init_vqs(portdev);
+ if (ret)
+ return ret;
+
+ if (use_multiport(portdev))
+ fill_queue(portdev->c_ivq, &portdev->cvq_lock);
+
+ list_for_each_entry(port, &portdev->ports, list) {
+ port->in_vq = portdev->in_vqs[port->id];
+ port->out_vq = portdev->out_vqs[port->id];
+
+ fill_queue(port->in_vq, &port->inbuf_lock);
+
+ /* Get port open/close status on the host */
+ send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
+ }
+ return 0;
+}
+#endif
+
static struct virtio_driver virtio_console = {
.feature_table = features,
.feature_table_size = ARRAY_SIZE(features),
From: Amit Shah <hidden> Date: 2011-12-07 10:56:56
On (Wed) 07 Dec 2011 [12:37:02], Michael S. Tsirkin wrote:
On Wed, Dec 07, 2011 at 01:18:44AM +0530, Amit Shah wrote:
quoted
Delete the vq and flush any pending requests from the block queue on the
freeze callback to prepare for hibernation.
Re-create the vq in the restore callback to resume normal function.
Signed-off-by: Amit Shah <redacted>
---
drivers/block/virtio_blk.c | 38 ++++++++++++++++++++++++++++++++++++++
1 files changed, 38 insertions(+), 0 deletions(-)
Thinking about it, looks like there's a bug in
virtblk_remove: if we get a config change after
flush_work we schedule another work.
That's a problem for sure as structure is removed.
So here, cancel_work_sync might still be running.
If it does run, might it try to access the device
config? Could not determine this quickly, if yes it's a problem.
Similar to the other comment: I don't see why just resetting device
can cause config queue access to go bad.
Amit
Yes, it could. So moving the cancel_delayed_work_sync() before
disabling napi would work fine?
No, because napi poll can schedule that.
Further, refill can reschedule itself.
It also looks like we have a bug in virtio net cleanup now:
cancel_delayed_work_sync is called after unregister, so
it will be calling napi API on an invalid device.
And, if it schedules itself it will run after device is gone.
I think we need some locking to fix this.
So here, cancel_work_sync might still be running.
If it does run, might it try to access the device
config? Could not determine this quickly, if yes it's a problem.
Similar to the other comment: I don't see why just resetting device
can cause config queue access to go bad.
Amit
From: "Michael S. Tsirkin" <mst@redhat.com> Date: 2011-12-07 15:57:11
On Wed, Dec 07, 2011 at 04:26:47PM +0530, Amit Shah wrote:
On (Wed) 07 Dec 2011 [12:37:02], Michael S. Tsirkin wrote:
quoted
On Wed, Dec 07, 2011 at 01:18:44AM +0530, Amit Shah wrote:
quoted
Delete the vq and flush any pending requests from the block queue on the
freeze callback to prepare for hibernation.
Re-create the vq in the restore callback to resume normal function.
Signed-off-by: Amit Shah <redacted>
---
drivers/block/virtio_blk.c | 38 ++++++++++++++++++++++++++++++++++++++
1 files changed, 38 insertions(+), 0 deletions(-)
@@ -568,6 +568,40 @@ static void __devexit virtblk_remove(struct virtio_device *vdev)ida_simple_remove(&vd_index_ida,index);}+#ifdef CONFIG_PM+staticintvirtblk_freeze(structvirtio_device*vdev)+{+structvirtio_blk*vblk=vdev->priv;++/* Ensure we don't receive any more interrupts */+vdev->config->reset(vdev);++flush_work(&vblk->config_work);
It bothers me that config work can be running
after reset here. If it does, it will not get sane
values from reading config.
Why so?
The reset only ensures the host doesn't write anything more, isn't it?
Why would the values be affected?
Generally, not only that. Reset also clears configuration to the
reset value :) As since accesses are done byte
by byte you might get a value that is different from
*both* old and new one as a result.
But that is a general comment, specifically for block,
I don't know if there is a problem with this.
Same for console.
quoted
Also, can there be stuff in the reqs list?
If yes is this a problem?
Should be all cleared by the two commands below. At least that's my
expectation. If not, let me know!
Thinking about it, looks like there's a bug in
virtblk_remove: if we get a config change after
flush_work we schedule another work.
That's a problem for sure as structure is removed.