diff mbox

[v5,5/7] KVM: Sending hyperlist to the host via hinting_vq

Message ID 20171128200324.4432-6-nilal@redhat.com (mailing list archive)
State New, archived
Headers show

Commit Message

Nitesh Lal Nov. 28, 2017, 8:03 p.m. UTC
From: Nitesh Narayan Lal <nilal@redhat.com>

This patch creates a new vq (hinting_vq) to be used for page hinting
and adds support in the existing virtio balloon infrastructure so
that the hyper list carrying pages which are supposed to be freed
could be sent to the host (QEMU) for processing by using hinting_vq.

Signed-off-by: Nitesh Narayan Lal <nilal@redhat.com>
---
 drivers/virtio/virtio_balloon.c     | 67 +++++++++++++++++++++++++++++++++----
 include/linux/page_hinting.h        | 16 +++++++++
 include/uapi/linux/virtio_balloon.h |  1 +
 virt/kvm/page_hinting.c             | 36 ++++++++------------
 4 files changed, 91 insertions(+), 29 deletions(-)
 create mode 100644 include/linux/page_hinting.h

Comments

kernel test robot Nov. 29, 2017, 1:01 p.m. UTC | #1
Hi Nitesh,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on kvm/linux-next]
[also build test WARNING on v4.15-rc1 next-20171128]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/nilal-redhat-com/KVM-Guest-page-hinting/20171129-180331
base:   https://git.kernel.org/pub/scm/virt/kvm/kvm.git linux-next
config: i386-randconfig-x016-201748 (attached as .config)
compiler: gcc-7 (Debian 7.2.0-12) 7.2.1 20171025
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All warnings (new ones prefixed by >>):

   drivers//virtio/virtio_balloon.c: In function 'tell_host_one_page':
>> drivers//virtio/virtio_balloon.c:107:28: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
     u64 gpaddr = virt_to_phys((void *)gvaddr);
                               ^
   drivers//virtio/virtio_balloon.c:110:39: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
     virtqueue_add_chain(vq, id, 0, NULL, (void *)gpaddr, NULL);
                                          ^
   drivers//virtio/virtio_balloon.c: In function 'virtballoon_page_hinting':
>> drivers//virtio/virtio_balloon.c:115:15: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
     u64 gvaddr = (u64)hypervisor_pagelist;
                  ^

vim +107 drivers//virtio/virtio_balloon.c

   101	
   102	#ifdef CONFIG_KVM_FREE_PAGE_HINTING
   103	static void tell_host_one_page(struct virtio_balloon *vb, struct virtqueue *vq,
   104				       u64 gvaddr, int len)
   105	{
   106		unsigned int id = VIRTQUEUE_DESC_ID_INIT;
 > 107		u64 gpaddr = virt_to_phys((void *)gvaddr);
   108	
   109		virtqueue_add_chain_desc(vq, gpaddr, len, &id, &id, 0);
   110		virtqueue_add_chain(vq, id, 0, NULL, (void *)gpaddr, NULL);
   111	}
   112	
   113	void virtballoon_page_hinting(struct virtio_balloon *vb, int hyper_entries)
   114	{
 > 115		u64 gvaddr = (u64)hypervisor_pagelist;
   116	
   117		vb->num_pfns = hyper_entries;
   118		tell_host_one_page(vb, vb->hinting_vq, gvaddr, hyper_entries);
   119	}
   120	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
kernel test robot Nov. 29, 2017, 1:42 p.m. UTC | #2
Hi Nitesh,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on kvm/linux-next]
[also build test WARNING on v4.15-rc1 next-20171128]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/nilal-redhat-com/KVM-Guest-page-hinting/20171129-180331
base:   https://git.kernel.org/pub/scm/virt/kvm/kvm.git linux-next
config: i386-randconfig-x008-201748 (attached as .config)
compiler: gcc-7 (Debian 7.2.0-12) 7.2.1 20171025
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All warnings (new ones prefixed by >>):

   drivers//virtio/virtio_balloon.c:59:6: error: #elif with no expression
    #elif
         ^
   drivers//virtio/virtio_balloon.c: In function 'fill_balloon':
   drivers//virtio/virtio_balloon.c:220:19: error: 'struct virtio_balloon' has no member named 'inflate_vq'
      tell_host(vb, vb->inflate_vq);
                      ^~
   drivers//virtio/virtio_balloon.c: In function 'leak_balloon':
   drivers//virtio/virtio_balloon.c:270:19: error: 'struct virtio_balloon' has no member named 'deflate_vq'
      tell_host(vb, vb->deflate_vq);
                      ^~
   drivers//virtio/virtio_balloon.c: In function 'stats_handle_request':
   drivers//virtio/virtio_balloon.c:343:11: error: 'struct virtio_balloon' has no member named 'stats_vq'; did you mean 'stats'?
     vq = vb->stats_vq;
              ^~~~~~~~
              stats
   drivers//virtio/virtio_balloon.c: In function 'init_vqs':
   drivers//virtio/virtio_balloon.c:454:12: error: 'hinting_ack' undeclared (first use in this function)
               hinting_ack };
               ^~~~~~~~~~~
   drivers//virtio/virtio_balloon.c:454:12: note: each undeclared identifier is reported only once for each function it appears in
   drivers//virtio/virtio_balloon.c:480:4: error: 'struct virtio_balloon' has no member named 'inflate_vq'
     vb->inflate_vq = vqs[0];
       ^~
   drivers//virtio/virtio_balloon.c:480:2: warning: statement with no effect [-Wunused-value]
     vb->inflate_vq = vqs[0];
     ^~
   drivers//virtio/virtio_balloon.c:481:4: error: 'struct virtio_balloon' has no member named 'deflate_vq'
     vb->deflate_vq = vqs[1];
       ^~
   drivers//virtio/virtio_balloon.c:481:2: warning: statement with no effect [-Wunused-value]
     vb->deflate_vq = vqs[1];
     ^~
   drivers//virtio/virtio_balloon.c:483:5: error: 'struct virtio_balloon' has no member named 'hinting_vq'
      vb->hinting_vq = vqs[3];
        ^~
   drivers//virtio/virtio_balloon.c:483:3: warning: statement with no effect [-Wunused-value]
      vb->hinting_vq = vqs[3];
      ^~
   drivers//virtio/virtio_balloon.c:487:7: error: 'struct virtio_balloon' has no member named 'stats_vq'; did you mean 'stats'?
      vb->stats_vq = vqs[2];
          ^~~~~~~~
          stats
   drivers//virtio/virtio_balloon.c:487:3: warning: statement with no effect [-Wunused-value]
      vb->stats_vq = vqs[2];
      ^~
   In file included from include/linux/string.h:6:0,
                    from include/linux/scatterlist.h:5,
                    from include/linux/virtio.h:7,
                    from drivers//virtio/virtio_balloon.c:22:
   drivers//virtio/virtio_balloon.c:496:32: error: 'struct virtio_balloon' has no member named 'stats_vq'; did you mean 'stats'?
      if (virtqueue_add_outbuf(vb->stats_vq, &sg, 1, vb, GFP_KERNEL)
                                   ^
   include/linux/compiler.h:58:30: note: in definition of macro '__trace_if'
     if (__builtin_constant_p(!!(cond)) ? !!(cond) :   \
                                 ^~~~
>> drivers//virtio/virtio_balloon.c:496:3: note: in expansion of macro 'if'
      if (virtqueue_add_outbuf(vb->stats_vq, &sg, 1, vb, GFP_KERNEL)
      ^~
   drivers//virtio/virtio_balloon.c:496:28: error: passing argument 1 of 'virtqueue_add_outbuf' from incompatible pointer type [-Werror=incompatible-pointer-types]
      if (virtqueue_add_outbuf(vb->stats_vq, &sg, 1, vb, GFP_KERNEL)
                               ^
   include/linux/compiler.h:58:30: note: in definition of macro '__trace_if'
     if (__builtin_constant_p(!!(cond)) ? !!(cond) :   \
                                 ^~~~
>> drivers//virtio/virtio_balloon.c:496:3: note: in expansion of macro 'if'
      if (virtqueue_add_outbuf(vb->stats_vq, &sg, 1, vb, GFP_KERNEL)
      ^~
   In file included from drivers//virtio/virtio_balloon.c:22:0:
   include/linux/virtio.h:38:5: note: expected 'struct virtqueue *' but argument is of type 'void (**)(struct virtqueue *)'
    int virtqueue_add_outbuf(struct virtqueue *vq,
        ^~~~~~~~~~~~~~~~~~~~
   In file included from include/linux/string.h:6:0,
                    from include/linux/scatterlist.h:5,
                    from include/linux/virtio.h:7,
                    from drivers//virtio/virtio_balloon.c:22:
   drivers//virtio/virtio_balloon.c:496:32: error: 'struct virtio_balloon' has no member named 'stats_vq'; did you mean 'stats'?
      if (virtqueue_add_outbuf(vb->stats_vq, &sg, 1, vb, GFP_KERNEL)
                                   ^
   include/linux/compiler.h:58:42: note: in definition of macro '__trace_if'
     if (__builtin_constant_p(!!(cond)) ? !!(cond) :   \
                                             ^~~~
>> drivers//virtio/virtio_balloon.c:496:3: note: in expansion of macro 'if'
      if (virtqueue_add_outbuf(vb->stats_vq, &sg, 1, vb, GFP_KERNEL)
      ^~
   drivers//virtio/virtio_balloon.c:496:28: error: passing argument 1 of 'virtqueue_add_outbuf' from incompatible pointer type [-Werror=incompatible-pointer-types]
      if (virtqueue_add_outbuf(vb->stats_vq, &sg, 1, vb, GFP_KERNEL)
                               ^
   include/linux/compiler.h:58:42: note: in definition of macro '__trace_if'
     if (__builtin_constant_p(!!(cond)) ? !!(cond) :   \
                                             ^~~~
>> drivers//virtio/virtio_balloon.c:496:3: note: in expansion of macro 'if'
      if (virtqueue_add_outbuf(vb->stats_vq, &sg, 1, vb, GFP_KERNEL)
      ^~
   In file included from drivers//virtio/virtio_balloon.c:22:0:
   include/linux/virtio.h:38:5: note: expected 'struct virtqueue *' but argument is of type 'void (**)(struct virtqueue *)'
    int virtqueue_add_outbuf(struct virtqueue *vq,
        ^~~~~~~~~~~~~~~~~~~~
   In file included from include/linux/string.h:6:0,
                    from include/linux/scatterlist.h:5,
                    from include/linux/virtio.h:7,
                    from drivers//virtio/virtio_balloon.c:22:
   drivers//virtio/virtio_balloon.c:496:32: error: 'struct virtio_balloon' has no member named 'stats_vq'; did you mean 'stats'?
      if (virtqueue_add_outbuf(vb->stats_vq, &sg, 1, vb, GFP_KERNEL)
                                   ^
   include/linux/compiler.h:69:16: note: in definition of macro '__trace_if'
      ______r = !!(cond);     \
                   ^~~~
>> drivers//virtio/virtio_balloon.c:496:3: note: in expansion of macro 'if'
      if (virtqueue_add_outbuf(vb->stats_vq, &sg, 1, vb, GFP_KERNEL)
      ^~
   drivers//virtio/virtio_balloon.c:496:28: error: passing argument 1 of 'virtqueue_add_outbuf' from incompatible pointer type [-Werror=incompatible-pointer-types]
      if (virtqueue_add_outbuf(vb->stats_vq, &sg, 1, vb, GFP_KERNEL)
                               ^
   include/linux/compiler.h:69:16: note: in definition of macro '__trace_if'
      ______r = !!(cond);     \
                   ^~~~
>> drivers//virtio/virtio_balloon.c:496:3: note: in expansion of macro 'if'
      if (virtqueue_add_outbuf(vb->stats_vq, &sg, 1, vb, GFP_KERNEL)
      ^~
   In file included from drivers//virtio/virtio_balloon.c:22:0:
   include/linux/virtio.h:38:5: note: expected 'struct virtqueue *' but argument is of type 'void (**)(struct virtqueue *)'
    int virtqueue_add_outbuf(struct virtqueue *vq,
        ^~~~~~~~~~~~~~~~~~~~
   drivers//virtio/virtio_balloon.c:499:22: error: 'struct virtio_balloon' has no member named 'stats_vq'; did you mean 'stats'?
      virtqueue_kick(vb->stats_vq);
                         ^~~~~~~~
                         stats
   drivers//virtio/virtio_balloon.c:499:18: error: passing argument 1 of 'virtqueue_kick' from incompatible pointer type [-Werror=incompatible-pointer-types]
      virtqueue_kick(vb->stats_vq);
                     ^~
   In file included from drivers//virtio/virtio_balloon.c:22:0:
   include/linux/virtio.h:80:6: note: expected 'struct virtqueue *' but argument is of type 'void (**)(struct virtqueue *)'
    bool virtqueue_kick(struct virtqueue *vq);
         ^~~~~~~~~~~~~~
   drivers//virtio/virtio_balloon.c: In function 'virtballoon_probe':
   drivers//virtio/virtio_balloon.c:646:32: error: 'virtballoon_page_hinting' undeclared (first use in this function); did you mean 'virtballoon_oom_notify'?
      request_hypercall = (void *)&virtballoon_page_hinting;
                                   ^~~~~~~~~~~~~~~~~~~~~~~~
                                   virtballoon_oom_notify
   In file included from include/linux/string.h:6:0,
                    from include/linux/scatterlist.h:5,
                    from include/linux/virtio.h:7,
                    from drivers//virtio/virtio_balloon.c:22:
   drivers//virtio/virtio_balloon.c: At top level:
   include/linux/compiler.h:64:4: warning: '______f' is static but declared in inline function 'strcpy' which is not static
       ______f = {     \
       ^
   include/linux/compiler.h:56:23: note: in expansion of macro '__trace_if'
    #define if(cond, ...) __trace_if( (cond , ## __VA_ARGS__) )
                          ^~~~~~~~~~
   include/linux/string.h:422:2: note: in expansion of macro 'if'
     if (p_size == (size_t)-1 && q_size == (size_t)-1)
     ^~
   include/linux/compiler.h:64:4: warning: '______f' is static but declared in inline function 'kmemdup' which is not static
       ______f = {     \
       ^
   include/linux/compiler.h:56:23: note: in expansion of macro '__trace_if'
    #define if(cond, ...) __trace_if( (cond , ## __VA_ARGS__) )
                          ^~~~~~~~~~
   include/linux/string.h:412:2: note: in expansion of macro 'if'
     if (p_size < size)
     ^~
   include/linux/compiler.h:64:4: warning: '______f' is static but declared in inline function 'kmemdup' which is not static
       ______f = {     \
       ^
   include/linux/compiler.h:56:23: note: in expansion of macro '__trace_if'
    #define if(cond, ...) __trace_if( (cond , ## __VA_ARGS__) )
                          ^~~~~~~~~~
   include/linux/string.h:410:2: note: in expansion of macro 'if'
     if (__builtin_constant_p(size) && p_size < size)
     ^~
   include/linux/compiler.h:64:4: warning: '______f' is static but declared in inline function 'memchr_inv' which is not static
       ______f = {     \
       ^
   include/linux/compiler.h:56:23: note: in expansion of macro '__trace_if'
    #define if(cond, ...) __trace_if( (cond , ## __VA_ARGS__) )
                          ^~~~~~~~~~
   include/linux/string.h:401:2: note: in expansion of macro 'if'
     if (p_size < size)
     ^~
   include/linux/compiler.h:64:4: warning: '______f' is static but declared in inline function 'memchr_inv' which is not static
       ______f = {     \
       ^
   include/linux/compiler.h:56:23: note: in expansion of macro '__trace_if'
    #define if(cond, ...) __trace_if( (cond , ## __VA_ARGS__) )
                          ^~~~~~~~~~
   include/linux/string.h:399:2: note: in expansion of macro 'if'
     if (__builtin_constant_p(size) && p_size < size)
     ^~
   include/linux/compiler.h:64:4: warning: '______f' is static but declared in inline function 'memchr' which is not static
       ______f = {     \
       ^
   include/linux/compiler.h:56:23: note: in expansion of macro '__trace_if'
    #define if(cond, ...) __trace_if( (cond , ## __VA_ARGS__) )
                          ^~~~~~~~~~
   include/linux/string.h:390:2: note: in expansion of macro 'if'
     if (p_size < size)
     ^~
   include/linux/compiler.h:64:4: warning: '______f' is static but declared in inline function 'memchr' which is not static
       ______f = {     \
       ^
   include/linux/compiler.h:56:23: note: in expansion of macro '__trace_if'
    #define if(cond, ...) __trace_if( (cond , ## __VA_ARGS__) )
                          ^~~~~~~~~~
   include/linux/string.h:388:2: note: in expansion of macro 'if'
     if (__builtin_constant_p(size) && p_size < size)
     ^~
   include/linux/compiler.h:64:4: warning: '______f' is static but declared in inline function 'memcmp' which is not static
       ______f = {     \
       ^
   include/linux/compiler.h:56:23: note: in expansion of macro '__trace_if'
    #define if(cond, ...) __trace_if( (cond , ## __VA_ARGS__) )
                          ^~~~~~~~~~
   include/linux/string.h:380:2: note: in expansion of macro 'if'
     if (p_size < size || q_size < size)
     ^~
   include/linux/compiler.h:64:4: warning: '______f' is static but declared in inline function 'memcmp' which is not static

vim +/if +496 drivers//virtio/virtio_balloon.c

6b35e4076 Rusty Russell      2008-02-04  449  
be91c33dd Amit Shah          2011-12-22  450  static int init_vqs(struct virtio_balloon *vb)
6b35e4076 Rusty Russell      2008-02-04  451  {
1006af9c7 Nitesh Narayan Lal 2017-11-28  452  	struct virtqueue *vqs[4];
1006af9c7 Nitesh Narayan Lal 2017-11-28  453  	vq_callback_t *callbacks[] = { balloon_ack, balloon_ack, stats_request,
1006af9c7 Nitesh Narayan Lal 2017-11-28  454  				       hinting_ack };
1006af9c7 Nitesh Narayan Lal 2017-11-28  455  	static const char * const names[] = { "inflate", "deflate", "stats",
1006af9c7 Nitesh Narayan Lal 2017-11-28  456  					      "hinting" };
9564e138b Adam Litke         2009-11-30  457  	int err, nvqs;
1006af9c7 Nitesh Narayan Lal 2017-11-28  458  	bool stats_vq_support, page_hinting_support;
6b35e4076 Rusty Russell      2008-02-04  459  
be91c33dd Amit Shah          2011-12-22  460  	/*
be91c33dd Amit Shah          2011-12-22  461  	 * We expect two virtqueues: inflate and deflate, and
1006af9c7 Nitesh Narayan Lal 2017-11-28  462  	 * optionally stat and hinting.
be91c33dd Amit Shah          2011-12-22  463  	 */
1006af9c7 Nitesh Narayan Lal 2017-11-28  464  	stats_vq_support = virtio_has_feature(vb->vdev,
1006af9c7 Nitesh Narayan Lal 2017-11-28  465  					      VIRTIO_BALLOON_F_STATS_VQ);
1006af9c7 Nitesh Narayan Lal 2017-11-28  466  	page_hinting_support = virtio_has_feature(vb->vdev,
1006af9c7 Nitesh Narayan Lal 2017-11-28  467  						  VIRTIO_GUEST_PAGE_HINTING_VQ
1006af9c7 Nitesh Narayan Lal 2017-11-28  468  						  );
1006af9c7 Nitesh Narayan Lal 2017-11-28  469  	if (stats_vq_support && page_hinting_support)
1006af9c7 Nitesh Narayan Lal 2017-11-28  470  		nvqs = 4;
1006af9c7 Nitesh Narayan Lal 2017-11-28  471  	else if (stats_vq_support || page_hinting_support)
1006af9c7 Nitesh Narayan Lal 2017-11-28  472  		nvqs = 3;
1006af9c7 Nitesh Narayan Lal 2017-11-28  473  	else
1006af9c7 Nitesh Narayan Lal 2017-11-28  474  		nvqs = 2;
1006af9c7 Nitesh Narayan Lal 2017-11-28  475  
9b2bbdb22 Michael S. Tsirkin 2017-03-06  476  	err = virtio_find_vqs(vb->vdev, nvqs, vqs, callbacks, names, NULL);
d2a7ddda9 Michael S. Tsirkin 2009-06-12  477  	if (err)
be91c33dd Amit Shah          2011-12-22  478  		return err;
6b35e4076 Rusty Russell      2008-02-04  479  
d2a7ddda9 Michael S. Tsirkin 2009-06-12  480  	vb->inflate_vq = vqs[0];
d2a7ddda9 Michael S. Tsirkin 2009-06-12  481  	vb->deflate_vq = vqs[1];
1006af9c7 Nitesh Narayan Lal 2017-11-28  482  	if (page_hinting_support)
1006af9c7 Nitesh Narayan Lal 2017-11-28  483  		vb->hinting_vq = vqs[3];
9564e138b Adam Litke         2009-11-30  484  	if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_STATS_VQ)) {
9564e138b Adam Litke         2009-11-30  485  		struct scatterlist sg;
9646b26e8 Ladi Prosek        2017-03-28  486  		unsigned int num_stats;
9564e138b Adam Litke         2009-11-30  487  		vb->stats_vq = vqs[2];
9564e138b Adam Litke         2009-11-30  488  
9564e138b Adam Litke         2009-11-30  489  		/*
9564e138b Adam Litke         2009-11-30  490  		 * Prime this virtqueue with one buffer so the hypervisor can
4951cc908 Rusty Russell      2014-03-13  491  		 * use it to signal us later (it can't be broken yet!).
9564e138b Adam Litke         2009-11-30  492  		 */
9646b26e8 Ladi Prosek        2017-03-28  493  		num_stats = update_balloon_stats(vb);
fc8653228 Ladi Prosek        2017-03-23  494  
9646b26e8 Ladi Prosek        2017-03-28  495  		sg_init_one(&sg, vb->stats, sizeof(vb->stats[0]) * num_stats);
92549abc6 Rusty Russell      2013-03-20 @496  		if (virtqueue_add_outbuf(vb->stats_vq, &sg, 1, vb, GFP_KERNEL)
f96fde41f Rusty Russell      2012-01-12  497  		    < 0)
9564e138b Adam Litke         2009-11-30  498  			BUG();
946cfe0e0 Michael S. Tsirkin 2010-04-12  499  		virtqueue_kick(vb->stats_vq);
9564e138b Adam Litke         2009-11-30  500  	}
be91c33dd Amit Shah          2011-12-22  501  	return 0;
be91c33dd Amit Shah          2011-12-22  502  }
be91c33dd Amit Shah          2011-12-22  503  

:::::: The code at line 496 was first introduced by commit
:::::: 92549abc6a6573294fc1bb9330db8b52dedfea5f virtio_balloon: use simplified virtqueue accessors.

:::::: TO: Rusty Russell <rusty@rustcorp.com.au>
:::::: CC: Rusty Russell <rusty@rustcorp.com.au>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
diff mbox

Patch

diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
index 7960746..f9e25b7 100644
--- a/drivers/virtio/virtio_balloon.c
+++ b/drivers/virtio/virtio_balloon.c
@@ -32,6 +32,7 @@ 
 #include <linux/mm.h>
 #include <linux/mount.h>
 #include <linux/magic.h>
+#include <linux/page_hinting.h>
 
 /*
  * Balloon device works in 4K page units.  So each page is pointed to by
@@ -53,8 +54,11 @@  static struct vfsmount *balloon_mnt;
 
 struct virtio_balloon {
 	struct virtio_device *vdev;
-	struct virtqueue *inflate_vq, *deflate_vq, *stats_vq;
-
+#ifdef CONFIG_KVM_FREE_PAGE_HINTING
+	struct virtqueue *inflate_vq, *deflate_vq, *stats_vq, *hinting_vq;
+#elif
+	struct virtqueue *inflate_vq, *deflate_vq, *stats_vq_vq;
+#endif
 	/* The balloon servicing is delegated to a freezable workqueue. */
 	struct work_struct update_balloon_stats_work;
 	struct work_struct update_balloon_size_work;
@@ -95,6 +99,33 @@  static struct virtio_device_id id_table[] = {
 	{ 0 },
 };
 
+#ifdef CONFIG_KVM_FREE_PAGE_HINTING
+static void tell_host_one_page(struct virtio_balloon *vb, struct virtqueue *vq,
+			       u64 gvaddr, int len)
+{
+	unsigned int id = VIRTQUEUE_DESC_ID_INIT;
+	u64 gpaddr = virt_to_phys((void *)gvaddr);
+
+	virtqueue_add_chain_desc(vq, gpaddr, len, &id, &id, 0);
+	virtqueue_add_chain(vq, id, 0, NULL, (void *)gpaddr, NULL);
+}
+
+void virtballoon_page_hinting(struct virtio_balloon *vb, int hyper_entries)
+{
+	u64 gvaddr = (u64)hypervisor_pagelist;
+
+	vb->num_pfns = hyper_entries;
+	tell_host_one_page(vb, vb->hinting_vq, gvaddr, hyper_entries);
+}
+
+static void hinting_ack(struct virtqueue *vq)
+{
+	struct virtio_balloon *vb = vq->vdev->priv;
+
+	wake_up(&vb->acked);
+}
+#endif
+
 static u32 page_to_balloon_pfn(struct page *page)
 {
 	unsigned long pfn = page_to_pfn(page);
@@ -418,22 +449,38 @@  static void update_balloon_size_func(struct work_struct *work)
 
 static int init_vqs(struct virtio_balloon *vb)
 {
-	struct virtqueue *vqs[3];
-	vq_callback_t *callbacks[] = { balloon_ack, balloon_ack, stats_request };
-	static const char * const names[] = { "inflate", "deflate", "stats" };
+	struct virtqueue *vqs[4];
+	vq_callback_t *callbacks[] = { balloon_ack, balloon_ack, stats_request,
+				       hinting_ack };
+	static const char * const names[] = { "inflate", "deflate", "stats",
+					      "hinting" };
 	int err, nvqs;
+	bool stats_vq_support, page_hinting_support;
 
 	/*
 	 * We expect two virtqueues: inflate and deflate, and
-	 * optionally stat.
+	 * optionally stat and hinting.
 	 */
-	nvqs = virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_STATS_VQ) ? 3 : 2;
+	stats_vq_support = virtio_has_feature(vb->vdev,
+					      VIRTIO_BALLOON_F_STATS_VQ);
+	page_hinting_support = virtio_has_feature(vb->vdev,
+						  VIRTIO_GUEST_PAGE_HINTING_VQ
+						  );
+	if (stats_vq_support && page_hinting_support)
+		nvqs = 4;
+	else if (stats_vq_support || page_hinting_support)
+		nvqs = 3;
+	else
+		nvqs = 2;
+
 	err = virtio_find_vqs(vb->vdev, nvqs, vqs, callbacks, names, NULL);
 	if (err)
 		return err;
 
 	vb->inflate_vq = vqs[0];
 	vb->deflate_vq = vqs[1];
+	if (page_hinting_support)
+		vb->hinting_vq = vqs[3];
 	if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_STATS_VQ)) {
 		struct scatterlist sg;
 		unsigned int num_stats;
@@ -595,6 +642,11 @@  static int virtballoon_probe(struct virtio_device *vdev)
 
 	virtio_device_ready(vdev);
 
+	if (virtio_has_feature(vb->vdev, VIRTIO_GUEST_PAGE_HINTING_VQ)) {
+		request_hypercall = (void *)&virtballoon_page_hinting;
+		balloon_ptr = vb;
+	}
+
 	if (towards_target(vb))
 		virtballoon_changed(vdev);
 	return 0;
@@ -683,6 +735,7 @@  static unsigned int features[] = {
 	VIRTIO_BALLOON_F_MUST_TELL_HOST,
 	VIRTIO_BALLOON_F_STATS_VQ,
 	VIRTIO_BALLOON_F_DEFLATE_ON_OOM,
+	VIRTIO_GUEST_PAGE_HINTING_VQ,
 };
 
 static struct virtio_driver virtio_balloon_driver = {
diff --git a/include/linux/page_hinting.h b/include/linux/page_hinting.h
new file mode 100644
index 0000000..0bfb646
--- /dev/null
+++ b/include/linux/page_hinting.h
@@ -0,0 +1,16 @@ 
+#define MAX_FGPT_ENTRIES	1000
+/*
+ * hypervisor_pages - It is a dummy structure passed with the hypercall.
+ * @pfn - page frame number for the page which is to be freed.
+ * @pages - number of pages which are supposed to be freed.
+ * A global array object is used to to hold the list of pfn and pages and is
+ * passed as part of the hypercall.
+ */
+struct hypervisor_pages {
+	unsigned long pfn;
+	unsigned int pages;
+};
+
+extern struct hypervisor_pages hypervisor_pagelist[MAX_FGPT_ENTRIES];
+extern void (*request_hypercall)(void *, int);
+extern void *balloon_ptr;
diff --git a/include/uapi/linux/virtio_balloon.h b/include/uapi/linux/virtio_balloon.h
index 343d7dd..45bdcc8 100644
--- a/include/uapi/linux/virtio_balloon.h
+++ b/include/uapi/linux/virtio_balloon.h
@@ -34,6 +34,7 @@ 
 #define VIRTIO_BALLOON_F_MUST_TELL_HOST	0 /* Tell before reclaiming pages */
 #define VIRTIO_BALLOON_F_STATS_VQ	1 /* Memory Stats virtqueue */
 #define VIRTIO_BALLOON_F_DEFLATE_ON_OOM	2 /* Deflate balloon on OOM */
+#define VIRTIO_GUEST_PAGE_HINTING_VQ	3 /* Page hinting virtqueue */
 
 /* Size of a PFN in the balloon interface. */
 #define VIRTIO_BALLOON_PFN_SHIFT 12
diff --git a/virt/kvm/page_hinting.c b/virt/kvm/page_hinting.c
index 54fe6bc..22c892b 100644
--- a/virt/kvm/page_hinting.c
+++ b/virt/kvm/page_hinting.c
@@ -5,8 +5,8 @@ 
 #include <linux/sort.h>
 #include <linux/kernel.h>
 #include <trace/events/kmem.h>
+#include <linux/page_hinting.h>
 
-#define MAX_FGPT_ENTRIES	1000
 #define HYPERLIST_THRESHOLD	500
 /*
  * struct kvm_free_pages - Tracks the pages which are freed by the guest.
@@ -21,22 +21,15 @@  struct kvm_free_pages {
 	unsigned int pages;
 };
 
-/*
- * hypervisor_pages - It is a dummy structure passed with the hypercall.
- * @pfn - page frame number for the page which is to be freed.
- * @pages - number of pages which are supposed to be freed.
- * A global array object is used to to hold the list of pfn and pages and is
- * passed as part of the hypercall.
- */
-struct hypervisor_pages {
-	unsigned long pfn;
-	unsigned int pages;
-};
-
 static __cacheline_aligned_in_smp DEFINE_SEQLOCK(guest_page_lock);
 DEFINE_PER_CPU(struct kvm_free_pages [MAX_FGPT_ENTRIES], kvm_pt);
 DEFINE_PER_CPU(int, kvm_pt_idx);
 struct hypervisor_pages hypervisor_pagelist[MAX_FGPT_ENTRIES];
+EXPORT_SYMBOL(hypervisor_pagelist);
+void (*request_hypercall)(void *, int);
+EXPORT_SYMBOL(request_hypercall);
+void *balloon_ptr;
+EXPORT_SYMBOL(balloon_ptr);
 
 static void empty_hyperlist(void)
 {
@@ -49,13 +42,11 @@  static void empty_hyperlist(void)
 	}
 }
 
-void make_hypercall(void)
+void hyperlist_ready(int entries)
 {
-	/*
-	 * Dummy function: Tobe filled later.
-	 */
-	empty_hyperlist();
 	trace_guest_str_dump("Hypercall to host...:");
+	request_hypercall(balloon_ptr, entries);
+	empty_hyperlist();
 }
 
 static int sort_pfn(const void *a1, const void *b1)
@@ -156,7 +147,7 @@  int compress_hyperlist(void)
 	if (merge_counter != 0)
 		ret = pack_hyperlist() - 1;
 	else
-		ret = MAX_FGPT_ENTRIES - 1;
+		ret = MAX_FGPT_ENTRIES;
 	return ret;
 }
 
@@ -227,16 +218,16 @@  void arch_free_page_slowpath(void)
 			 */
 			if (!prev_free) {
 				hyper_idx++;
-				hypervisor_pagelist[hyper_idx].pfn = pfn;
-				hypervisor_pagelist[hyper_idx].pages = 1;
 				trace_guest_free_page_slowpath(
 				hypervisor_pagelist[hyper_idx].pfn,
 				hypervisor_pagelist[hyper_idx].pages);
+				hypervisor_pagelist[hyper_idx].pfn = pfn;
+				hypervisor_pagelist[hyper_idx].pages = 1;
 				if (hyper_idx == MAX_FGPT_ENTRIES - 1) {
 					hyper_idx =  compress_hyperlist();
 					if (hyper_idx >=
 					    HYPERLIST_THRESHOLD) {
-						make_hypercall();
+						hyperlist_ready(hyper_idx);
 						hyper_idx = 0;
 					}
 				}
@@ -272,6 +263,7 @@  void arch_alloc_page(struct page *page, int order)
 	 * free pages is full and a hypercall will be made. Until complete free
 	 * page list is traversed no further allocaiton will be allowed.
 	 */
+
 	do {
 		seq = read_seqbegin(&guest_page_lock);
 	} while (read_seqretry(&guest_page_lock, seq));