Message ID | ad580b4d5b76c18fe2fe409704f25622e01af361.1589926004.git.anchalag@amazon.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | Fix PM hibernation in Xen guests | expand |
Hi Anchal, Thank you for the patch! Yet something to improve: [auto build test ERROR on linus/master] [also build test ERROR on v5.7-rc6] [cannot apply to xen-tip/linux-next tip/irq/core tip/auto-latest next-20200519] [if your patch is applied to the wrong git tree, please drop us a note to help improve the system. BTW, we also suggest to use '--base' option to specify the base tree in git format-patch, please see https://stackoverflow.com/a/37406982] url: https://github.com/0day-ci/linux/commits/Anchal-Agarwal/Fix-PM-hibernation-in-Xen-guests/20200520-073211 base: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 03fb3acae4be8a6b680ffedb220a8b6c07260b40 config: x86_64-randconfig-a016-20200519 (attached as .config) compiler: clang version 11.0.0 (https://github.com/llvm/llvm-project e6658079aca6d971b4e9d7137a3a2ecbc9c34aec) reproduce: wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # install x86_64 cross compiling tool for clang build # apt-get install binutils-x86-64-linux-gnu # save the attached .config to linux build tree COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=x86_64 If you fix the issue, kindly add following tag as appropriate Reported-by: kbuild test robot <lkp@intel.com> All error/warnings (new ones prefixed by >>, old ones prefixed by <<): >> drivers/block/xen-blkfront.c:2699:30: warning: missing terminating '"' character [-Winvalid-pp-token] xenbus_dev_error(dev, err, "Hibernation Failed. ^ >> drivers/block/xen-blkfront.c:2699:30: error: expected expression drivers/block/xen-blkfront.c:2700:26: warning: missing terminating '"' character [-Winvalid-pp-token] The ring is still busy"); ^ >> drivers/block/xen-blkfront.c:2726:1: error: function definition is not allowed here { ^ >> drivers/block/xen-blkfront.c:2762:10: error: use of undeclared identifier 'blkfront_restore' .thaw = blkfront_restore, ^ drivers/block/xen-blkfront.c:2763:13: error: use of undeclared identifier 'blkfront_restore' .restore = blkfront_restore ^ drivers/block/xen-blkfront.c:2767:1: error: function definition is not allowed here { ^ drivers/block/xen-blkfront.c:2800:1: error: function definition is not allowed here { ^ drivers/block/xen-blkfront.c:2822:1: error: function definition is not allowed here { ^ >> drivers/block/xen-blkfront.c:2863:13: error: use of undeclared identifier 'xlblk_init' module_init(xlblk_init); ^ drivers/block/xen-blkfront.c:2867:1: error: function definition is not allowed here { ^ >> drivers/block/xen-blkfront.c:2874:13: error: use of undeclared identifier 'xlblk_exit' module_exit(xlblk_exit); ^ >> drivers/block/xen-blkfront.c:2880:24: error: expected '}' MODULE_ALIAS("xenblk"); ^ drivers/block/xen-blkfront.c:2674:1: note: to match this '{' { ^ >> drivers/block/xen-blkfront.c:2738:45: warning: ISO C90 forbids mixing declarations and code [-Wdeclaration-after-statement] static const struct block_device_operations xlvbd_block_fops = ^ 3 warnings and 11 errors generated. vim +2699 drivers/block/xen-blkfront.c 2672 2673 static int blkfront_freeze(struct xenbus_device *dev) 2674 { 2675 unsigned int i; 2676 struct blkfront_info *info = dev_get_drvdata(&dev->dev); 2677 struct blkfront_ring_info *rinfo; 2678 /* This would be reasonable timeout as used in xenbus_dev_shutdown() */ 2679 unsigned int timeout = 5 * HZ; 2680 unsigned long flags; 2681 int err = 0; 2682 2683 info->connected = BLKIF_STATE_FREEZING; 2684 2685 blk_mq_freeze_queue(info->rq); 2686 blk_mq_quiesce_queue(info->rq); 2687 2688 for_each_rinfo(info, rinfo, i) { 2689 /* No more gnttab callback work. */ 2690 gnttab_cancel_free_callback(&rinfo->callback); 2691 /* Flush gnttab callback work. Must be done with no locks held. */ 2692 flush_work(&rinfo->work); 2693 } 2694 2695 for_each_rinfo(info, rinfo, i) { 2696 spin_lock_irqsave(&rinfo->ring_lock, flags); 2697 if (RING_FULL(&rinfo->ring) 2698 || RING_HAS_UNCONSUMED_RESPONSES(&rinfo->ring)) { > 2699 xenbus_dev_error(dev, err, "Hibernation Failed. 2700 The ring is still busy"); 2701 info->connected = BLKIF_STATE_CONNECTED; 2702 spin_unlock_irqrestore(&rinfo->ring_lock, flags); 2703 return -EBUSY; 2704 } 2705 spin_unlock_irqrestore(&rinfo->ring_lock, flags); 2706 } 2707 /* Kick the backend to disconnect */ 2708 xenbus_switch_state(dev, XenbusStateClosing); 2709 2710 /* 2711 * We don't want to move forward before the frontend is diconnected 2712 * from the backend cleanly. 2713 */ 2714 timeout = wait_for_completion_timeout(&info->wait_backend_disconnected, 2715 timeout); 2716 if (!timeout) { 2717 err = -EBUSY; 2718 xenbus_dev_error(dev, err, "Freezing timed out;" 2719 "the device may become inconsistent state"); 2720 } 2721 2722 return err; 2723 } 2724 2725 static int blkfront_restore(struct xenbus_device *dev) > 2726 { 2727 struct blkfront_info *info = dev_get_drvdata(&dev->dev); 2728 int err = 0; 2729 2730 err = talk_to_blkback(dev, info); 2731 blk_mq_unquiesce_queue(info->rq); 2732 blk_mq_unfreeze_queue(info->rq); 2733 if (!err) 2734 blk_mq_update_nr_hw_queues(&info->tag_set, info->nr_rings); 2735 return err; 2736 } 2737 > 2738 static const struct block_device_operations xlvbd_block_fops = 2739 { 2740 .owner = THIS_MODULE, 2741 .open = blkif_open, 2742 .release = blkif_release, 2743 .getgeo = blkif_getgeo, 2744 .ioctl = blkif_ioctl, 2745 .compat_ioctl = blkdev_compat_ptr_ioctl, 2746 }; 2747 2748 2749 static const struct xenbus_device_id blkfront_ids[] = { 2750 { "vbd" }, 2751 { "" } 2752 }; 2753 2754 static struct xenbus_driver blkfront_driver = { 2755 .ids = blkfront_ids, 2756 .probe = blkfront_probe, 2757 .remove = blkfront_remove, 2758 .resume = blkfront_resume, 2759 .otherend_changed = blkback_changed, 2760 .is_ready = blkfront_is_ready, 2761 .freeze = blkfront_freeze, > 2762 .thaw = blkfront_restore, 2763 .restore = blkfront_restore 2764 }; 2765 2766 static void purge_persistent_grants(struct blkfront_info *info) > 2767 { 2768 unsigned int i; 2769 unsigned long flags; 2770 struct blkfront_ring_info *rinfo; 2771 2772 for_each_rinfo(info, rinfo, i) { 2773 struct grant *gnt_list_entry, *tmp; 2774 2775 spin_lock_irqsave(&rinfo->ring_lock, flags); 2776 2777 if (rinfo->persistent_gnts_c == 0) { 2778 spin_unlock_irqrestore(&rinfo->ring_lock, flags); 2779 continue; 2780 } 2781 2782 list_for_each_entry_safe(gnt_list_entry, tmp, &rinfo->grants, 2783 node) { 2784 if (gnt_list_entry->gref == GRANT_INVALID_REF || 2785 gnttab_query_foreign_access(gnt_list_entry->gref)) 2786 continue; 2787 2788 list_del(&gnt_list_entry->node); 2789 gnttab_end_foreign_access(gnt_list_entry->gref, 0, 0UL); 2790 rinfo->persistent_gnts_c--; 2791 gnt_list_entry->gref = GRANT_INVALID_REF; 2792 list_add_tail(&gnt_list_entry->node, &rinfo->grants); 2793 } 2794 2795 spin_unlock_irqrestore(&rinfo->ring_lock, flags); 2796 } 2797 } 2798 2799 static void blkfront_delay_work(struct work_struct *work) 2800 { 2801 struct blkfront_info *info; 2802 bool need_schedule_work = false; 2803 2804 mutex_lock(&blkfront_mutex); 2805 2806 list_for_each_entry(info, &info_list, info_list) { 2807 if (info->feature_persistent) { 2808 need_schedule_work = true; 2809 mutex_lock(&info->mutex); 2810 purge_persistent_grants(info); 2811 mutex_unlock(&info->mutex); 2812 } 2813 } 2814 2815 if (need_schedule_work) 2816 schedule_delayed_work(&blkfront_work, HZ * 10); 2817 2818 mutex_unlock(&blkfront_mutex); 2819 } 2820 2821 static int __init xlblk_init(void) > 2822 { 2823 int ret; 2824 int nr_cpus = num_online_cpus(); 2825 2826 if (!xen_domain()) 2827 return -ENODEV; 2828 2829 if (!xen_has_pv_disk_devices()) 2830 return -ENODEV; 2831 2832 if (register_blkdev(XENVBD_MAJOR, DEV_NAME)) { 2833 pr_warn("xen_blk: can't get major %d with name %s\n", 2834 XENVBD_MAJOR, DEV_NAME); 2835 return -ENODEV; 2836 } 2837 2838 if (xen_blkif_max_segments < BLKIF_MAX_SEGMENTS_PER_REQUEST) 2839 xen_blkif_max_segments = BLKIF_MAX_SEGMENTS_PER_REQUEST; 2840 2841 if (xen_blkif_max_ring_order > XENBUS_MAX_RING_GRANT_ORDER) { 2842 pr_info("Invalid max_ring_order (%d), will use default max: %d.\n", 2843 xen_blkif_max_ring_order, XENBUS_MAX_RING_GRANT_ORDER); 2844 xen_blkif_max_ring_order = XENBUS_MAX_RING_GRANT_ORDER; 2845 } 2846 2847 if (xen_blkif_max_queues > nr_cpus) { 2848 pr_info("Invalid max_queues (%d), will use default max: %d.\n", 2849 xen_blkif_max_queues, nr_cpus); 2850 xen_blkif_max_queues = nr_cpus; 2851 } 2852 2853 INIT_DELAYED_WORK(&blkfront_work, blkfront_delay_work); 2854 2855 ret = xenbus_register_frontend(&blkfront_driver); 2856 if (ret) { 2857 unregister_blkdev(XENVBD_MAJOR, DEV_NAME); 2858 return ret; 2859 } 2860 2861 return 0; 2862 } > 2863 module_init(xlblk_init); 2864 2865 2866 static void __exit xlblk_exit(void) 2867 { 2868 cancel_delayed_work_sync(&blkfront_work); 2869 2870 xenbus_unregister_driver(&blkfront_driver); 2871 unregister_blkdev(XENVBD_MAJOR, DEV_NAME); 2872 kfree(minors); 2873 } > 2874 module_exit(xlblk_exit); 2875 2876 MODULE_DESCRIPTION("Xen virtual block device frontend"); 2877 MODULE_LICENSE("GPL"); 2878 MODULE_ALIAS_BLOCKDEV_MAJOR(XENVBD_MAJOR); 2879 MODULE_ALIAS("xen:vbd"); > 2880 MODULE_ALIAS("xenblk"); --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
Hi Anchal, Thank you for the patch! Yet something to improve: [auto build test ERROR on linus/master] [also build test ERROR on v5.7-rc6] [cannot apply to xen-tip/linux-next tip/irq/core tip/auto-latest next-20200519] [if your patch is applied to the wrong git tree, please drop us a note to help improve the system. BTW, we also suggest to use '--base' option to specify the base tree in git format-patch, please see https://stackoverflow.com/a/37406982] url: https://github.com/0day-ci/linux/commits/Anchal-Agarwal/Fix-PM-hibernation-in-Xen-guests/20200520-073211 base: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 03fb3acae4be8a6b680ffedb220a8b6c07260b40 config: x86_64-rhel (attached as .config) compiler: gcc-7 (Ubuntu 7.5.0-6ubuntu2) 7.5.0 reproduce: # save the attached .config to linux build tree make ARCH=x86_64 If you fix the issue, kindly add following tag as appropriate Reported-by: kbuild test robot <lkp@intel.com> All error/warnings (new ones prefixed by >>, old ones prefixed by <<): drivers/block/xen-blkfront.c: In function 'blkfront_freeze': >> drivers/block/xen-blkfront.c:2699:30: warning: missing terminating " character xenbus_dev_error(dev, err, "Hibernation Failed. ^ >> drivers/block/xen-blkfront.c:2699:30: error: missing terminating " character xenbus_dev_error(dev, err, "Hibernation Failed. ^~~~~~~~~~~~~~~~~~~~ >> drivers/block/xen-blkfront.c:2700:4: error: 'The' undeclared (first use in this function) The ring is still busy"); ^~~ drivers/block/xen-blkfront.c:2700:4: note: each undeclared identifier is reported only once for each function it appears in >> drivers/block/xen-blkfront.c:2700:8: error: expected ')' before 'ring' The ring is still busy"); ^~~~ drivers/block/xen-blkfront.c:2700:26: warning: missing terminating " character The ring is still busy"); ^ drivers/block/xen-blkfront.c:2700:26: error: missing terminating " character The ring is still busy"); ^~~ >> drivers/block/xen-blkfront.c:2704:2: error: expected ';' before '}' token } ^ vim +2699 drivers/block/xen-blkfront.c 2672 2673 static int blkfront_freeze(struct xenbus_device *dev) 2674 { 2675 unsigned int i; 2676 struct blkfront_info *info = dev_get_drvdata(&dev->dev); 2677 struct blkfront_ring_info *rinfo; 2678 /* This would be reasonable timeout as used in xenbus_dev_shutdown() */ 2679 unsigned int timeout = 5 * HZ; 2680 unsigned long flags; 2681 int err = 0; 2682 2683 info->connected = BLKIF_STATE_FREEZING; 2684 2685 blk_mq_freeze_queue(info->rq); 2686 blk_mq_quiesce_queue(info->rq); 2687 2688 for_each_rinfo(info, rinfo, i) { 2689 /* No more gnttab callback work. */ 2690 gnttab_cancel_free_callback(&rinfo->callback); 2691 /* Flush gnttab callback work. Must be done with no locks held. */ 2692 flush_work(&rinfo->work); 2693 } 2694 2695 for_each_rinfo(info, rinfo, i) { 2696 spin_lock_irqsave(&rinfo->ring_lock, flags); 2697 if (RING_FULL(&rinfo->ring) 2698 || RING_HAS_UNCONSUMED_RESPONSES(&rinfo->ring)) { > 2699 xenbus_dev_error(dev, err, "Hibernation Failed. > 2700 The ring is still busy"); 2701 info->connected = BLKIF_STATE_CONNECTED; 2702 spin_unlock_irqrestore(&rinfo->ring_lock, flags); 2703 return -EBUSY; > 2704 } 2705 spin_unlock_irqrestore(&rinfo->ring_lock, flags); 2706 } 2707 /* Kick the backend to disconnect */ 2708 xenbus_switch_state(dev, XenbusStateClosing); 2709 2710 /* 2711 * We don't want to move forward before the frontend is diconnected 2712 * from the backend cleanly. 2713 */ 2714 timeout = wait_for_completion_timeout(&info->wait_backend_disconnected, 2715 timeout); 2716 if (!timeout) { 2717 err = -EBUSY; 2718 xenbus_dev_error(dev, err, "Freezing timed out;" 2719 "the device may become inconsistent state"); 2720 } 2721 2722 return err; 2723 } 2724 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
Hi Anchal,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on linus/master]
[also build test WARNING on v5.7-rc6]
[cannot apply to xen-tip/linux-next tip/irq/core tip/auto-latest next-20200519]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]
url: https://github.com/0day-ci/linux/commits/Anchal-Agarwal/Fix-PM-hibernation-in-Xen-guests/20200520-073211
base: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 03fb3acae4be8a6b680ffedb220a8b6c07260b40
config: x86_64-allmodconfig (attached as .config)
reproduce:
# apt-get install sparse
# sparse version: v0.6.1-193-gb8fad4bc-dirty
# save the attached .config to linux build tree
make C=1 ARCH=x86_64 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__'
:::::: branch date: 11 hours ago
:::::: commit date: 11 hours ago
If you fix the issue, kindly add following tag as appropriate
Reported-by: kbuild test robot <lkp@intel.com>
sparse warnings: (new ones prefixed by >>)
>> drivers/block/xen-blkfront.c:2700:0: sparse: sparse: missing terminating " character
drivers/block/xen-blkfront.c:2701:0: sparse: sparse: missing terminating " character
drivers/block/xen-blkfront.c:2700:25: sparse: sparse: Expected ) in function call
drivers/block/xen-blkfront.c:2700:25: sparse: sparse: got The
# https://github.com/0day-ci/linux/commit/1997467d18e784a64ee0fe00875492e9605f6147
git remote add linux-review https://github.com/0day-ci/linux
git remote update linux-review
git checkout 1997467d18e784a64ee0fe00875492e9605f6147
vim +2700 drivers/block/xen-blkfront.c
9f27ee59503865 Jeremy Fitzhardinge 2007-07-17 2672
1997467d18e784 Munehisa Kamata 2020-05-19 2673 static int blkfront_freeze(struct xenbus_device *dev)
1997467d18e784 Munehisa Kamata 2020-05-19 2674 {
1997467d18e784 Munehisa Kamata 2020-05-19 2675 unsigned int i;
1997467d18e784 Munehisa Kamata 2020-05-19 2676 struct blkfront_info *info = dev_get_drvdata(&dev->dev);
1997467d18e784 Munehisa Kamata 2020-05-19 2677 struct blkfront_ring_info *rinfo;
1997467d18e784 Munehisa Kamata 2020-05-19 2678 /* This would be reasonable timeout as used in xenbus_dev_shutdown() */
1997467d18e784 Munehisa Kamata 2020-05-19 2679 unsigned int timeout = 5 * HZ;
1997467d18e784 Munehisa Kamata 2020-05-19 2680 unsigned long flags;
1997467d18e784 Munehisa Kamata 2020-05-19 2681 int err = 0;
1997467d18e784 Munehisa Kamata 2020-05-19 2682
1997467d18e784 Munehisa Kamata 2020-05-19 2683 info->connected = BLKIF_STATE_FREEZING;
1997467d18e784 Munehisa Kamata 2020-05-19 2684
1997467d18e784 Munehisa Kamata 2020-05-19 2685 blk_mq_freeze_queue(info->rq);
1997467d18e784 Munehisa Kamata 2020-05-19 2686 blk_mq_quiesce_queue(info->rq);
1997467d18e784 Munehisa Kamata 2020-05-19 2687
1997467d18e784 Munehisa Kamata 2020-05-19 2688 for_each_rinfo(info, rinfo, i) {
1997467d18e784 Munehisa Kamata 2020-05-19 2689 /* No more gnttab callback work. */
1997467d18e784 Munehisa Kamata 2020-05-19 2690 gnttab_cancel_free_callback(&rinfo->callback);
1997467d18e784 Munehisa Kamata 2020-05-19 2691 /* Flush gnttab callback work. Must be done with no locks held. */
1997467d18e784 Munehisa Kamata 2020-05-19 2692 flush_work(&rinfo->work);
1997467d18e784 Munehisa Kamata 2020-05-19 2693 }
1997467d18e784 Munehisa Kamata 2020-05-19 2694
1997467d18e784 Munehisa Kamata 2020-05-19 2695 for_each_rinfo(info, rinfo, i) {
1997467d18e784 Munehisa Kamata 2020-05-19 2696 spin_lock_irqsave(&rinfo->ring_lock, flags);
1997467d18e784 Munehisa Kamata 2020-05-19 2697 if (RING_FULL(&rinfo->ring)
1997467d18e784 Munehisa Kamata 2020-05-19 2698 || RING_HAS_UNCONSUMED_RESPONSES(&rinfo->ring)) {
1997467d18e784 Munehisa Kamata 2020-05-19 2699 xenbus_dev_error(dev, err, "Hibernation Failed.
1997467d18e784 Munehisa Kamata 2020-05-19 @2700 The ring is still busy");
1997467d18e784 Munehisa Kamata 2020-05-19 2701 info->connected = BLKIF_STATE_CONNECTED;
1997467d18e784 Munehisa Kamata 2020-05-19 2702 spin_unlock_irqrestore(&rinfo->ring_lock, flags);
1997467d18e784 Munehisa Kamata 2020-05-19 2703 return -EBUSY;
1997467d18e784 Munehisa Kamata 2020-05-19 2704 }
1997467d18e784 Munehisa Kamata 2020-05-19 2705 spin_unlock_irqrestore(&rinfo->ring_lock, flags);
1997467d18e784 Munehisa Kamata 2020-05-19 2706 }
1997467d18e784 Munehisa Kamata 2020-05-19 2707 /* Kick the backend to disconnect */
1997467d18e784 Munehisa Kamata 2020-05-19 2708 xenbus_switch_state(dev, XenbusStateClosing);
1997467d18e784 Munehisa Kamata 2020-05-19 2709
1997467d18e784 Munehisa Kamata 2020-05-19 2710 /*
1997467d18e784 Munehisa Kamata 2020-05-19 2711 * We don't want to move forward before the frontend is diconnected
1997467d18e784 Munehisa Kamata 2020-05-19 2712 * from the backend cleanly.
1997467d18e784 Munehisa Kamata 2020-05-19 2713 */
1997467d18e784 Munehisa Kamata 2020-05-19 2714 timeout = wait_for_completion_timeout(&info->wait_backend_disconnected,
1997467d18e784 Munehisa Kamata 2020-05-19 2715 timeout);
1997467d18e784 Munehisa Kamata 2020-05-19 2716 if (!timeout) {
1997467d18e784 Munehisa Kamata 2020-05-19 2717 err = -EBUSY;
1997467d18e784 Munehisa Kamata 2020-05-19 2718 xenbus_dev_error(dev, err, "Freezing timed out;"
1997467d18e784 Munehisa Kamata 2020-05-19 2719 "the device may become inconsistent state");
1997467d18e784 Munehisa Kamata 2020-05-19 2720 }
1997467d18e784 Munehisa Kamata 2020-05-19 2721
1997467d18e784 Munehisa Kamata 2020-05-19 2722 return err;
1997467d18e784 Munehisa Kamata 2020-05-19 2723 }
1997467d18e784 Munehisa Kamata 2020-05-19 2724
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
On Tue, May 19, 2020 at 11:27:50PM +0000, Anchal Agarwal wrote: > From: Munehisa Kamata <kamatam@amazon.com> > > S4 power transition states are much different than xen > suspend/resume. Former is visible to the guest and frontend drivers should > be aware of the state transitions and should be able to take appropriate > actions when needed. In transition to S4 we need to make sure that at least > all the in-flight blkif requests get completed, since they probably contain > bits of the guest's memory image and that's not going to get saved any > other way. Hence, re-issuing of in-flight requests as in case of xen resume > will not work here. This is in contrast to xen-suspend where we need to > freeze with as little processing as possible to avoid dirtying RAM late in > the migration cycle and we know that in-flight data can wait. > > Add freeze, thaw and restore callbacks for PM suspend and hibernation > support. All frontend drivers that needs to use PM_HIBERNATION/PM_SUSPEND > events, need to implement these xenbus_driver callbacks. The freeze handler > stops block-layer queue and disconnect the frontend from the backend while > freeing ring_info and associated resources. Before disconnecting from the > backend, we need to prevent any new IO from being queued and wait for existing > IO to complete. Freeze/unfreeze of the queues will guarantee that there are no > requests in use on the shared ring. However, for sanity we should check > state of the ring before disconnecting to make sure that there are no > outstanding requests to be processed on the ring. The restore handler > re-allocates ring_info, unquiesces and unfreezes the queue and re-connect to > the backend, so that rest of the kernel can continue to use the block device > transparently. > > Note:For older backends,if a backend doesn't have commit'12ea729645ace' > xen/blkback: unmap all persistent grants when frontend gets disconnected, > the frontend may see massive amount of grant table warning when freeing > resources. > [ 36.852659] deferring g.e. 0xf9 (pfn 0xffffffffffffffff) > [ 36.855089] xen:grant_table: WARNING:e.g. 0x112 still in use! > > In this case, persistent grants would need to be disabled. > > [Anchal Changelog: Removed timeout/request during blkfront freeze. > Reworked the whole patch to work with blk-mq and incorporate upstream's > comments] Please tag versions using vX and it would be helpful if you could list the specific changes that you performed between versions. There where 3 RFC versions IIRC, and there's no log of the changes between them. > > Signed-off-by: Anchal Agarwal <anchalag@amazon.com> > Signed-off-by: Munehisa Kamata <kamatam@amazon.com> > --- > drivers/block/xen-blkfront.c | 122 +++++++++++++++++++++++++++++++++-- > 1 file changed, 115 insertions(+), 7 deletions(-) > > diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c > index 3b889ea950c2..464863ed7093 100644 > --- a/drivers/block/xen-blkfront.c > +++ b/drivers/block/xen-blkfront.c > @@ -48,6 +48,8 @@ > #include <linux/list.h> > #include <linux/workqueue.h> > #include <linux/sched/mm.h> > +#include <linux/completion.h> > +#include <linux/delay.h> > > #include <xen/xen.h> > #include <xen/xenbus.h> > @@ -80,6 +82,8 @@ enum blkif_state { > BLKIF_STATE_DISCONNECTED, > BLKIF_STATE_CONNECTED, > BLKIF_STATE_SUSPENDED, > + BLKIF_STATE_FREEZING, > + BLKIF_STATE_FROZEN Nit: adding a terminating ',' would prevent further additions from having to modify this line. > }; > > struct grant { > @@ -219,6 +223,7 @@ struct blkfront_info > struct list_head requests; > struct bio_list bio_list; > struct list_head info_list; > + struct completion wait_backend_disconnected; > }; > > static unsigned int nr_minors; > @@ -1005,6 +1010,7 @@ static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size, > info->sector_size = sector_size; > info->physical_sector_size = physical_sector_size; > blkif_set_queue_limits(info); > + init_completion(&info->wait_backend_disconnected); > > return 0; > } > @@ -1057,7 +1063,7 @@ static int xen_translate_vdev(int vdevice, int *minor, unsigned int *offset) > case XEN_SCSI_DISK5_MAJOR: > case XEN_SCSI_DISK6_MAJOR: > case XEN_SCSI_DISK7_MAJOR: > - *offset = (*minor / PARTS_PER_DISK) + > + *offset = (*minor / PARTS_PER_DISK) + > ((major - XEN_SCSI_DISK1_MAJOR + 1) * 16) + > EMULATED_SD_DISK_NAME_OFFSET; > *minor = *minor + > @@ -1072,7 +1078,7 @@ static int xen_translate_vdev(int vdevice, int *minor, unsigned int *offset) > case XEN_SCSI_DISK13_MAJOR: > case XEN_SCSI_DISK14_MAJOR: > case XEN_SCSI_DISK15_MAJOR: > - *offset = (*minor / PARTS_PER_DISK) + > + *offset = (*minor / PARTS_PER_DISK) + Unrelated changes, please split to a pre-patch. > ((major - XEN_SCSI_DISK8_MAJOR + 8) * 16) + > EMULATED_SD_DISK_NAME_OFFSET; > *minor = *minor + > @@ -1353,6 +1359,8 @@ static void blkif_free(struct blkfront_info *info, int suspend) > unsigned int i; > struct blkfront_ring_info *rinfo; > > + if (info->connected == BLKIF_STATE_FREEZING) > + goto free_rings; > /* Prevent new requests being issued until we fix things up. */ > info->connected = suspend ? > BLKIF_STATE_SUSPENDED : BLKIF_STATE_DISCONNECTED; > @@ -1360,6 +1368,7 @@ static void blkif_free(struct blkfront_info *info, int suspend) > if (info->rq) > blk_mq_stop_hw_queues(info->rq); > > +free_rings: > for_each_rinfo(info, rinfo, i) > blkif_free_ring(rinfo); > > @@ -1563,8 +1572,10 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id) > struct blkfront_ring_info *rinfo = (struct blkfront_ring_info *)dev_id; > struct blkfront_info *info = rinfo->dev_info; > > - if (unlikely(info->connected != BLKIF_STATE_CONNECTED)) > - return IRQ_HANDLED; > + if (unlikely(info->connected != BLKIF_STATE_CONNECTED > + && info->connected != BLKIF_STATE_FREEZING)){ Extra tab and missing space between '){'. Also my preference would be for the && to go at the end of the previous line, like it's done elsewhere in the file. > + return IRQ_HANDLED; > + } > > spin_lock_irqsave(&rinfo->ring_lock, flags); > again: > @@ -2027,6 +2038,7 @@ static int blkif_recover(struct blkfront_info *info) > unsigned int segs; > struct blkfront_ring_info *rinfo; > > + bool frozen = info->connected == BLKIF_STATE_FROZEN; Please put this together with the rest of the variable definitions, and leave the empty line as a split between variable definitions and code. I've already requested this on RFC v3 but you seem to have dropped some of the requests I've made there. > blkfront_gather_backend_features(info); > /* Reset limits changed by blk_mq_update_nr_hw_queues(). */ > blkif_set_queue_limits(info); > @@ -2048,6 +2060,9 @@ static int blkif_recover(struct blkfront_info *info) > kick_pending_request_queues(rinfo); > } > > + if (frozen) > + return 0; > + > list_for_each_entry_safe(req, n, &info->requests, queuelist) { > /* Requeue pending requests (flush or discard) */ > list_del_init(&req->queuelist); > @@ -2364,6 +2379,7 @@ static void blkfront_connect(struct blkfront_info *info) > > return; > case BLKIF_STATE_SUSPENDED: > + case BLKIF_STATE_FROZEN: > /* > * If we are recovering from suspension, we need to wait > * for the backend to announce it's features before > @@ -2481,12 +2497,36 @@ static void blkback_changed(struct xenbus_device *dev, > break; > > case XenbusStateClosed: > - if (dev->state == XenbusStateClosed) > + if (dev->state == XenbusStateClosed) { > + if (info->connected == BLKIF_STATE_FREEZING) { > + blkif_free(info, 0); > + info->connected = BLKIF_STATE_FROZEN; > + complete(&info->wait_backend_disconnected); > + break; There's no need for the break here, you can rely on the break below. > + } > + > break; > + } > + > + /* > + * We may somehow receive backend's Closed again while thawing > + * or restoring and it causes thawing or restoring to fail. > + * Ignore such unexpected state regardless of the backend state. > + */ > + if (info->connected == BLKIF_STATE_FROZEN) { I think you can join this with the previous dev->state == XenbusStateClosed? Also, won't the device be in the Closed state already if it's in state frozen? > + dev_dbg(&dev->dev, > + "ignore the backend's Closed state: %s", > + dev->nodename); > + break; > + } > /* fall through */ > case XenbusStateClosing: > - if (info) > - blkfront_closing(info); > + if (info) { > + if (info->connected == BLKIF_STATE_FREEZING) > + xenbus_frontend_closed(dev); > + else > + blkfront_closing(info); > + } > break; > } > } > @@ -2630,6 +2670,71 @@ static void blkif_release(struct gendisk *disk, fmode_t mode) > mutex_unlock(&blkfront_mutex); > } > > +static int blkfront_freeze(struct xenbus_device *dev) > +{ > + unsigned int i; > + struct blkfront_info *info = dev_get_drvdata(&dev->dev); > + struct blkfront_ring_info *rinfo; > + /* This would be reasonable timeout as used in xenbus_dev_shutdown() */ > + unsigned int timeout = 5 * HZ; > + unsigned long flags; > + int err = 0; > + > + info->connected = BLKIF_STATE_FREEZING; > + > + blk_mq_freeze_queue(info->rq); > + blk_mq_quiesce_queue(info->rq); > + > + for_each_rinfo(info, rinfo, i) { > + /* No more gnttab callback work. */ > + gnttab_cancel_free_callback(&rinfo->callback); > + /* Flush gnttab callback work. Must be done with no locks held. */ > + flush_work(&rinfo->work); > + } > + > + for_each_rinfo(info, rinfo, i) { > + spin_lock_irqsave(&rinfo->ring_lock, flags); > + if (RING_FULL(&rinfo->ring) > + || RING_HAS_UNCONSUMED_RESPONSES(&rinfo->ring)) { '||' should go at the end of the previous line. > + xenbus_dev_error(dev, err, "Hibernation Failed. > + The ring is still busy"); > + info->connected = BLKIF_STATE_CONNECTED; > + spin_unlock_irqrestore(&rinfo->ring_lock, flags); You need to unfreeze the queues here, or else the device will be in a blocked state AFAICT. > + return -EBUSY; > + } > + spin_unlock_irqrestore(&rinfo->ring_lock, flags); > + } This block has indentation all messed up. > + /* Kick the backend to disconnect */ > + xenbus_switch_state(dev, XenbusStateClosing); > + > + /* > + * We don't want to move forward before the frontend is diconnected > + * from the backend cleanly. > + */ > + timeout = wait_for_completion_timeout(&info->wait_backend_disconnected, > + timeout); > + if (!timeout) { > + err = -EBUSY; Note err is only used here, and I think could just be dropped. > + xenbus_dev_error(dev, err, "Freezing timed out;" > + "the device may become inconsistent state"); Leaving the device in this state is quite bad, as it's in a closed state and with the queues frozen. You should make an attempt to restore things to a working state. > + } > + > + return err; > +} > + > +static int blkfront_restore(struct xenbus_device *dev) > +{ > + struct blkfront_info *info = dev_get_drvdata(&dev->dev); > + int err = 0; > + > + err = talk_to_blkback(dev, info); > + blk_mq_unquiesce_queue(info->rq); > + blk_mq_unfreeze_queue(info->rq); > + if (!err) > + blk_mq_update_nr_hw_queues(&info->tag_set, info->nr_rings); Bad indentation. Also shouldn't you first update the queues and then unfreeze them? Thanks, Roger.
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 3b889ea950c2..464863ed7093 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -48,6 +48,8 @@ #include <linux/list.h> #include <linux/workqueue.h> #include <linux/sched/mm.h> +#include <linux/completion.h> +#include <linux/delay.h> #include <xen/xen.h> #include <xen/xenbus.h> @@ -80,6 +82,8 @@ enum blkif_state { BLKIF_STATE_DISCONNECTED, BLKIF_STATE_CONNECTED, BLKIF_STATE_SUSPENDED, + BLKIF_STATE_FREEZING, + BLKIF_STATE_FROZEN }; struct grant { @@ -219,6 +223,7 @@ struct blkfront_info struct list_head requests; struct bio_list bio_list; struct list_head info_list; + struct completion wait_backend_disconnected; }; static unsigned int nr_minors; @@ -1005,6 +1010,7 @@ static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size, info->sector_size = sector_size; info->physical_sector_size = physical_sector_size; blkif_set_queue_limits(info); + init_completion(&info->wait_backend_disconnected); return 0; } @@ -1057,7 +1063,7 @@ static int xen_translate_vdev(int vdevice, int *minor, unsigned int *offset) case XEN_SCSI_DISK5_MAJOR: case XEN_SCSI_DISK6_MAJOR: case XEN_SCSI_DISK7_MAJOR: - *offset = (*minor / PARTS_PER_DISK) + + *offset = (*minor / PARTS_PER_DISK) + ((major - XEN_SCSI_DISK1_MAJOR + 1) * 16) + EMULATED_SD_DISK_NAME_OFFSET; *minor = *minor + @@ -1072,7 +1078,7 @@ static int xen_translate_vdev(int vdevice, int *minor, unsigned int *offset) case XEN_SCSI_DISK13_MAJOR: case XEN_SCSI_DISK14_MAJOR: case XEN_SCSI_DISK15_MAJOR: - *offset = (*minor / PARTS_PER_DISK) + + *offset = (*minor / PARTS_PER_DISK) + ((major - XEN_SCSI_DISK8_MAJOR + 8) * 16) + EMULATED_SD_DISK_NAME_OFFSET; *minor = *minor + @@ -1353,6 +1359,8 @@ static void blkif_free(struct blkfront_info *info, int suspend) unsigned int i; struct blkfront_ring_info *rinfo; + if (info->connected == BLKIF_STATE_FREEZING) + goto free_rings; /* Prevent new requests being issued until we fix things up. */ info->connected = suspend ? BLKIF_STATE_SUSPENDED : BLKIF_STATE_DISCONNECTED; @@ -1360,6 +1368,7 @@ static void blkif_free(struct blkfront_info *info, int suspend) if (info->rq) blk_mq_stop_hw_queues(info->rq); +free_rings: for_each_rinfo(info, rinfo, i) blkif_free_ring(rinfo); @@ -1563,8 +1572,10 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id) struct blkfront_ring_info *rinfo = (struct blkfront_ring_info *)dev_id; struct blkfront_info *info = rinfo->dev_info; - if (unlikely(info->connected != BLKIF_STATE_CONNECTED)) - return IRQ_HANDLED; + if (unlikely(info->connected != BLKIF_STATE_CONNECTED + && info->connected != BLKIF_STATE_FREEZING)){ + return IRQ_HANDLED; + } spin_lock_irqsave(&rinfo->ring_lock, flags); again: @@ -2027,6 +2038,7 @@ static int blkif_recover(struct blkfront_info *info) unsigned int segs; struct blkfront_ring_info *rinfo; + bool frozen = info->connected == BLKIF_STATE_FROZEN; blkfront_gather_backend_features(info); /* Reset limits changed by blk_mq_update_nr_hw_queues(). */ blkif_set_queue_limits(info); @@ -2048,6 +2060,9 @@ static int blkif_recover(struct blkfront_info *info) kick_pending_request_queues(rinfo); } + if (frozen) + return 0; + list_for_each_entry_safe(req, n, &info->requests, queuelist) { /* Requeue pending requests (flush or discard) */ list_del_init(&req->queuelist); @@ -2364,6 +2379,7 @@ static void blkfront_connect(struct blkfront_info *info) return; case BLKIF_STATE_SUSPENDED: + case BLKIF_STATE_FROZEN: /* * If we are recovering from suspension, we need to wait * for the backend to announce it's features before @@ -2481,12 +2497,36 @@ static void blkback_changed(struct xenbus_device *dev, break; case XenbusStateClosed: - if (dev->state == XenbusStateClosed) + if (dev->state == XenbusStateClosed) { + if (info->connected == BLKIF_STATE_FREEZING) { + blkif_free(info, 0); + info->connected = BLKIF_STATE_FROZEN; + complete(&info->wait_backend_disconnected); + break; + } + break; + } + + /* + * We may somehow receive backend's Closed again while thawing + * or restoring and it causes thawing or restoring to fail. + * Ignore such unexpected state regardless of the backend state. + */ + if (info->connected == BLKIF_STATE_FROZEN) { + dev_dbg(&dev->dev, + "ignore the backend's Closed state: %s", + dev->nodename); + break; + } /* fall through */ case XenbusStateClosing: - if (info) - blkfront_closing(info); + if (info) { + if (info->connected == BLKIF_STATE_FREEZING) + xenbus_frontend_closed(dev); + else + blkfront_closing(info); + } break; } } @@ -2630,6 +2670,71 @@ static void blkif_release(struct gendisk *disk, fmode_t mode) mutex_unlock(&blkfront_mutex); } +static int blkfront_freeze(struct xenbus_device *dev) +{ + unsigned int i; + struct blkfront_info *info = dev_get_drvdata(&dev->dev); + struct blkfront_ring_info *rinfo; + /* This would be reasonable timeout as used in xenbus_dev_shutdown() */ + unsigned int timeout = 5 * HZ; + unsigned long flags; + int err = 0; + + info->connected = BLKIF_STATE_FREEZING; + + blk_mq_freeze_queue(info->rq); + blk_mq_quiesce_queue(info->rq); + + for_each_rinfo(info, rinfo, i) { + /* No more gnttab callback work. */ + gnttab_cancel_free_callback(&rinfo->callback); + /* Flush gnttab callback work. Must be done with no locks held. */ + flush_work(&rinfo->work); + } + + for_each_rinfo(info, rinfo, i) { + spin_lock_irqsave(&rinfo->ring_lock, flags); + if (RING_FULL(&rinfo->ring) + || RING_HAS_UNCONSUMED_RESPONSES(&rinfo->ring)) { + xenbus_dev_error(dev, err, "Hibernation Failed. + The ring is still busy"); + info->connected = BLKIF_STATE_CONNECTED; + spin_unlock_irqrestore(&rinfo->ring_lock, flags); + return -EBUSY; + } + spin_unlock_irqrestore(&rinfo->ring_lock, flags); + } + /* Kick the backend to disconnect */ + xenbus_switch_state(dev, XenbusStateClosing); + + /* + * We don't want to move forward before the frontend is diconnected + * from the backend cleanly. + */ + timeout = wait_for_completion_timeout(&info->wait_backend_disconnected, + timeout); + if (!timeout) { + err = -EBUSY; + xenbus_dev_error(dev, err, "Freezing timed out;" + "the device may become inconsistent state"); + } + + return err; +} + +static int blkfront_restore(struct xenbus_device *dev) +{ + struct blkfront_info *info = dev_get_drvdata(&dev->dev); + int err = 0; + + err = talk_to_blkback(dev, info); + blk_mq_unquiesce_queue(info->rq); + blk_mq_unfreeze_queue(info->rq); + if (!err) + blk_mq_update_nr_hw_queues(&info->tag_set, info->nr_rings); + return err; +} + static const struct block_device_operations xlvbd_block_fops = { .owner = THIS_MODULE, @@ -2653,6 +2758,9 @@ static struct xenbus_driver blkfront_driver = { .resume = blkfront_resume, .otherend_changed = blkback_changed, .is_ready = blkfront_is_ready, + .freeze = blkfront_freeze, + .thaw = blkfront_restore, + .restore = blkfront_restore }; static void purge_persistent_grants(struct blkfront_info *info)