aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndres Lagar-Cavilla <andres@lagarcavilla.org>2012-09-14 10:26:59 -0400
committerKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>2012-09-21 09:23:51 -0400
commitc571898ffc24a1768e1b2dabeac0fc7dd4c14601 (patch)
tree65070baf01dd31aecfb9c15d2a3c1fa20fdba0da
parentc3cb4709809e655a4ba5a716086c8bc5bbbbccdb (diff)
xen/gndev: Xen backend support for paged out grant targets V4.
Since Xen-4.2, hvm domains may have portions of their memory paged out. When a foreign domain (such as dom0) attempts to map these frames, the map will initially fail. The hypervisor returns a suitable errno, and kicks an asynchronous page-in operation carried out by a helper. The foreign domain is expected to retry the mapping operation until it eventually succeeds. The foreign domain is not put to sleep because itself could be the one running the pager assist (typical scenario for dom0). This patch adds support for this mechanism for backend drivers using grant mapping and copying operations. Specifically, this covers the blkback and gntdev drivers (which map foreign grants), and the netback driver (which copies foreign grants). * Add a retry method for grants that fail with GNTST_eagain (i.e. because the target foreign frame is paged out). * Insert hooks with appropriate wrappers in the aforementioned drivers. The retry loop is only invoked if the grant operation status is GNTST_eagain. It guarantees to leave a new status code different from GNTST_eagain. Any other status code results in identical code execution as before. The retry loop performs 256 attempts with increasing time intervals through a 32 second period. It uses msleep to yield while waiting for the next retry. V2 after feedback from David Vrabel: * Explicit MAX_DELAY instead of wrap-around delay into zero * Abstract GNTST_eagain check into core grant table code for netback module. V3 after feedback from Ian Campbell: * Add placeholder in array of grant table error descriptions for unrelated error code we jump over. * Eliminate single map and retry macro in favor of a generic batch flavor. * Some renaming. * Bury most implementation in grant_table.c, cleaner interface. V4 rebased on top of sync of Xen grant table interface headers. Signed-off-by: Andres Lagar-Cavilla <andres@lagarcavilla.org> Acked-by: Ian Campbell <ian.campbell@citrix.com> [v5: Fixed whitespace issues] Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
-rw-r--r--drivers/net/xen-netback/netback.c11
-rw-r--r--drivers/xen/grant-table.c53
-rw-r--r--drivers/xen/xenbus/xenbus_client.c6
-rw-r--r--include/xen/grant_table.h12
4 files changed, 70 insertions, 12 deletions
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
index 682633bfe00f..05593d882023 100644
--- a/drivers/net/xen-netback/netback.c
+++ b/drivers/net/xen-netback/netback.c
@@ -635,9 +635,7 @@ static void xen_netbk_rx_action(struct xen_netbk *netbk)
635 return; 635 return;
636 636
637 BUG_ON(npo.copy_prod > ARRAY_SIZE(netbk->grant_copy_op)); 637 BUG_ON(npo.copy_prod > ARRAY_SIZE(netbk->grant_copy_op));
638 ret = HYPERVISOR_grant_table_op(GNTTABOP_copy, &netbk->grant_copy_op, 638 gnttab_batch_copy(netbk->grant_copy_op, npo.copy_prod);
639 npo.copy_prod);
640 BUG_ON(ret != 0);
641 639
642 while ((skb = __skb_dequeue(&rxq)) != NULL) { 640 while ((skb = __skb_dequeue(&rxq)) != NULL) {
643 sco = (struct skb_cb_overlay *)skb->cb; 641 sco = (struct skb_cb_overlay *)skb->cb;
@@ -1460,18 +1458,15 @@ static void xen_netbk_tx_submit(struct xen_netbk *netbk)
1460static void xen_netbk_tx_action(struct xen_netbk *netbk) 1458static void xen_netbk_tx_action(struct xen_netbk *netbk)
1461{ 1459{
1462 unsigned nr_gops; 1460 unsigned nr_gops;
1463 int ret;
1464 1461
1465 nr_gops = xen_netbk_tx_build_gops(netbk); 1462 nr_gops = xen_netbk_tx_build_gops(netbk);
1466 1463
1467 if (nr_gops == 0) 1464 if (nr_gops == 0)
1468 return; 1465 return;
1469 ret = HYPERVISOR_grant_table_op(GNTTABOP_copy,
1470 netbk->tx_copy_ops, nr_gops);
1471 BUG_ON(ret);
1472 1466
1473 xen_netbk_tx_submit(netbk); 1467 gnttab_batch_copy(netbk->tx_copy_ops, nr_gops);
1474 1468
1469 xen_netbk_tx_submit(netbk);
1475} 1470}
1476 1471
1477static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx) 1472static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx)
diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c
index eea81cf8a2a5..3a567b15600b 100644
--- a/drivers/xen/grant-table.c
+++ b/drivers/xen/grant-table.c
@@ -38,6 +38,7 @@
38#include <linux/vmalloc.h> 38#include <linux/vmalloc.h>
39#include <linux/uaccess.h> 39#include <linux/uaccess.h>
40#include <linux/io.h> 40#include <linux/io.h>
41#include <linux/delay.h>
41#include <linux/hardirq.h> 42#include <linux/hardirq.h>
42 43
43#include <xen/xen.h> 44#include <xen/xen.h>
@@ -823,6 +824,52 @@ unsigned int gnttab_max_grant_frames(void)
823} 824}
824EXPORT_SYMBOL_GPL(gnttab_max_grant_frames); 825EXPORT_SYMBOL_GPL(gnttab_max_grant_frames);
825 826
827/* Handling of paged out grant targets (GNTST_eagain) */
828#define MAX_DELAY 256
829static inline void
830gnttab_retry_eagain_gop(unsigned int cmd, void *gop, int16_t *status,
831 const char *func)
832{
833 unsigned delay = 1;
834
835 do {
836 BUG_ON(HYPERVISOR_grant_table_op(cmd, gop, 1));
837 if (*status == GNTST_eagain)
838 msleep(delay++);
839 } while ((*status == GNTST_eagain) && (delay < MAX_DELAY));
840
841 if (delay >= MAX_DELAY) {
842 printk(KERN_ERR "%s: %s eagain grant\n", func, current->comm);
843 *status = GNTST_bad_page;
844 }
845}
846
847void gnttab_batch_map(struct gnttab_map_grant_ref *batch, unsigned count)
848{
849 struct gnttab_map_grant_ref *op;
850
851 if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, batch, count))
852 BUG();
853 for (op = batch; op < batch + count; op++)
854 if (op->status == GNTST_eagain)
855 gnttab_retry_eagain_gop(GNTTABOP_map_grant_ref, op,
856 &op->status, __func__);
857}
858EXPORT_SYMBOL_GPL(gnttab_batch_map);
859
860void gnttab_batch_copy(struct gnttab_copy *batch, unsigned count)
861{
862 struct gnttab_copy *op;
863
864 if (HYPERVISOR_grant_table_op(GNTTABOP_copy, batch, count))
865 BUG();
866 for (op = batch; op < batch + count; op++)
867 if (op->status == GNTST_eagain)
868 gnttab_retry_eagain_gop(GNTTABOP_copy, op,
869 &op->status, __func__);
870}
871EXPORT_SYMBOL_GPL(gnttab_batch_copy);
872
826int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops, 873int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops,
827 struct gnttab_map_grant_ref *kmap_ops, 874 struct gnttab_map_grant_ref *kmap_ops,
828 struct page **pages, unsigned int count) 875 struct page **pages, unsigned int count)
@@ -836,6 +883,12 @@ int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops,
836 if (ret) 883 if (ret)
837 return ret; 884 return ret;
838 885
886 /* Retry eagain maps */
887 for (i = 0; i < count; i++)
888 if (map_ops[i].status == GNTST_eagain)
889 gnttab_retry_eagain_gop(GNTTABOP_map_grant_ref, map_ops + i,
890 &map_ops[i].status, __func__);
891
839 if (xen_feature(XENFEAT_auto_translated_physmap)) 892 if (xen_feature(XENFEAT_auto_translated_physmap))
840 return ret; 893 return ret;
841 894
diff --git a/drivers/xen/xenbus/xenbus_client.c b/drivers/xen/xenbus/xenbus_client.c
index b3e146edb51d..bcf3ba4a6ec1 100644
--- a/drivers/xen/xenbus/xenbus_client.c
+++ b/drivers/xen/xenbus/xenbus_client.c
@@ -490,8 +490,7 @@ static int xenbus_map_ring_valloc_pv(struct xenbus_device *dev,
490 490
491 op.host_addr = arbitrary_virt_to_machine(pte).maddr; 491 op.host_addr = arbitrary_virt_to_machine(pte).maddr;
492 492
493 if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1)) 493 gnttab_batch_map(&op, 1);
494 BUG();
495 494
496 if (op.status != GNTST_okay) { 495 if (op.status != GNTST_okay) {
497 free_vm_area(area); 496 free_vm_area(area);
@@ -572,8 +571,7 @@ int xenbus_map_ring(struct xenbus_device *dev, int gnt_ref,
572 gnttab_set_map_op(&op, (unsigned long)vaddr, GNTMAP_host_map, gnt_ref, 571 gnttab_set_map_op(&op, (unsigned long)vaddr, GNTMAP_host_map, gnt_ref,
573 dev->otherend_id); 572 dev->otherend_id);
574 573
575 if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1)) 574 gnttab_batch_map(&op, 1);
576 BUG();
577 575
578 if (op.status != GNTST_okay) { 576 if (op.status != GNTST_okay) {
579 xenbus_dev_fatal(dev, op.status, 577 xenbus_dev_fatal(dev, op.status,
diff --git a/include/xen/grant_table.h b/include/xen/grant_table.h
index 11e27c3af3cb..ba0d77529a29 100644
--- a/include/xen/grant_table.h
+++ b/include/xen/grant_table.h
@@ -189,4 +189,16 @@ int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops,
189int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops, 189int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops,
190 struct page **pages, unsigned int count, bool clear_pte); 190 struct page **pages, unsigned int count, bool clear_pte);
191 191
192/* Perform a batch of grant map/copy operations. Retry every batch slot
193 * for which the hypervisor returns GNTST_eagain. This is typically due
194 * to paged out target frames.
195 *
196 * Will retry for 1, 2, ... 255 ms, i.e. 256 times during 32 seconds.
197 *
198 * Return value in each iand every status field of the batch guaranteed
199 * to not be GNTST_eagain.
200 */
201void gnttab_batch_map(struct gnttab_map_grant_ref *batch, unsigned count);
202void gnttab_batch_copy(struct gnttab_copy *batch, unsigned count);
203
192#endif /* __ASM_GNTTAB_H__ */ 204#endif /* __ASM_GNTTAB_H__ */