xen: branch for v5.19-rc1
-----BEGIN PGP SIGNATURE----- iHUEABYIAB0WIQRTLbB6QfY48x44uB6AXGG7T9hjvgUCYosaQAAKCRCAXGG7T9hj vil9AP9b4C+f9LTG0kAinjxLPyWE0Mo/iq3gO60MteZ2HyeI+AD/eSzJioJA0vyH 4pnU/UaGLJSp/B1LitLdjwoWIvwcEws= =pDcW -----END PGP SIGNATURE----- Merge tag 'for-linus-5.19-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip Pull xen updates from Juergen Gross: - decouple the PV interface from kernel internals in the Xen scsifront/scsiback pv drivers - harden the Xen scsifront PV driver against a malicious backend driver - simplify Xen PV frontend driver ring page setup - support Xen setups with multiple domains created at boot time to tolerate Xenstore coming up late - two small cleanup patches * tag 'for-linus-5.19-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip: (29 commits) xen: add support for initializing xenstore later as HVM domain xen: sync xs_wire.h header with upstream xen x86: xen: remove STACK_FRAME_NON_STANDARD from xen_cpuid xen-blk{back,front}: Update contact points for buffer_squeeze_duration_ms and feature_persistent xen/xenbus: eliminate xenbus_grant_ring() xen/sndfront: use xenbus_setup_ring() and xenbus_teardown_ring() xen/usbfront: use xenbus_setup_ring() and xenbus_teardown_ring() xen/scsifront: use xenbus_setup_ring() and xenbus_teardown_ring() xen/pcifront: use xenbus_setup_ring() and xenbus_teardown_ring() xen/drmfront: use xenbus_setup_ring() and xenbus_teardown_ring() xen/tpmfront: use xenbus_setup_ring() and xenbus_teardown_ring() xen/netfront: use xenbus_setup_ring() and xenbus_teardown_ring() xen/blkfront: use xenbus_setup_ring() and xenbus_teardown_ring() xen/xenbus: add xenbus_setup_ring() service function xen: update ring.h xen/shbuf: switch xen-front-pgdir-shbuf to use INVALID_GRANT_REF xen/dmabuf: switch gntdev-dmabuf to use INVALID_GRANT_REF xen/sound: switch xen_snd_front to use INVALID_GRANT_REF xen/drm: switch xen_drm_front to use INVALID_GRANT_REF xen/usb: switch xen-hcd to use INVALID_GRANT_REF ...
This commit is contained in:
Коммит
d613060475
|
@ -29,7 +29,7 @@ Description:
|
|||
What: /sys/module/xen_blkback/parameters/buffer_squeeze_duration_ms
|
||||
Date: December 2019
|
||||
KernelVersion: 5.6
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: Maximilian Heyne <mheyne@amazon.de>
|
||||
Description:
|
||||
When memory pressure is reported to blkback this option
|
||||
controls the duration in milliseconds that blkback will not
|
||||
|
@ -39,7 +39,7 @@ Description:
|
|||
What: /sys/module/xen_blkback/parameters/feature_persistent
|
||||
Date: September 2020
|
||||
KernelVersion: 5.10
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: Maximilian Heyne <mheyne@amazon.de>
|
||||
Description:
|
||||
Whether to enable the persistent grants feature or not. Note
|
||||
that this option only takes effect on newly created backends.
|
||||
|
|
|
@ -12,7 +12,7 @@ Description:
|
|||
What: /sys/module/xen_blkfront/parameters/feature_persistent
|
||||
Date: September 2020
|
||||
KernelVersion: 5.10
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: Maximilian Heyne <mheyne@amazon.de>
|
||||
Description:
|
||||
Whether to enable the persistent grants feature or not. Note
|
||||
that this option only takes effect on newly created frontends.
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
#include <linux/pci.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/edd.h>
|
||||
#include <linux/objtool.h>
|
||||
|
||||
#include <xen/xen.h>
|
||||
#include <xen/events.h>
|
||||
|
@ -165,7 +164,6 @@ static void xen_cpuid(unsigned int *ax, unsigned int *bx,
|
|||
|
||||
*bx &= maskebx;
|
||||
}
|
||||
STACK_FRAME_NON_STANDARD(xen_cpuid); /* XEN_EMULATE_PREFIX */
|
||||
|
||||
static bool __init xen_check_mwait(void)
|
||||
{
|
||||
|
|
|
@ -229,8 +229,6 @@ static unsigned int nr_minors;
|
|||
static unsigned long *minors;
|
||||
static DEFINE_SPINLOCK(minor_lock);
|
||||
|
||||
#define GRANT_INVALID_REF 0
|
||||
|
||||
#define PARTS_PER_DISK 16
|
||||
#define PARTS_PER_EXT_DISK 256
|
||||
|
||||
|
@ -321,7 +319,7 @@ static int fill_grant_buffer(struct blkfront_ring_info *rinfo, int num)
|
|||
gnt_list_entry->page = granted_page;
|
||||
}
|
||||
|
||||
gnt_list_entry->gref = GRANT_INVALID_REF;
|
||||
gnt_list_entry->gref = INVALID_GRANT_REF;
|
||||
list_add(&gnt_list_entry->node, &rinfo->grants);
|
||||
i++;
|
||||
}
|
||||
|
@ -350,7 +348,7 @@ static struct grant *get_free_grant(struct blkfront_ring_info *rinfo)
|
|||
node);
|
||||
list_del(&gnt_list_entry->node);
|
||||
|
||||
if (gnt_list_entry->gref != GRANT_INVALID_REF)
|
||||
if (gnt_list_entry->gref != INVALID_GRANT_REF)
|
||||
rinfo->persistent_gnts_c--;
|
||||
|
||||
return gnt_list_entry;
|
||||
|
@ -372,7 +370,7 @@ static struct grant *get_grant(grant_ref_t *gref_head,
|
|||
struct grant *gnt_list_entry = get_free_grant(rinfo);
|
||||
struct blkfront_info *info = rinfo->dev_info;
|
||||
|
||||
if (gnt_list_entry->gref != GRANT_INVALID_REF)
|
||||
if (gnt_list_entry->gref != INVALID_GRANT_REF)
|
||||
return gnt_list_entry;
|
||||
|
||||
/* Assign a gref to this page */
|
||||
|
@ -396,7 +394,7 @@ static struct grant *get_indirect_grant(grant_ref_t *gref_head,
|
|||
struct grant *gnt_list_entry = get_free_grant(rinfo);
|
||||
struct blkfront_info *info = rinfo->dev_info;
|
||||
|
||||
if (gnt_list_entry->gref != GRANT_INVALID_REF)
|
||||
if (gnt_list_entry->gref != INVALID_GRANT_REF)
|
||||
return gnt_list_entry;
|
||||
|
||||
/* Assign a gref to this page */
|
||||
|
@ -1221,7 +1219,7 @@ static void blkif_free_ring(struct blkfront_ring_info *rinfo)
|
|||
list_for_each_entry_safe(persistent_gnt, n,
|
||||
&rinfo->grants, node) {
|
||||
list_del(&persistent_gnt->node);
|
||||
if (persistent_gnt->gref != GRANT_INVALID_REF) {
|
||||
if (persistent_gnt->gref != INVALID_GRANT_REF) {
|
||||
gnttab_end_foreign_access(persistent_gnt->gref,
|
||||
0UL);
|
||||
rinfo->persistent_gnts_c--;
|
||||
|
@ -1282,15 +1280,8 @@ free_shadow:
|
|||
flush_work(&rinfo->work);
|
||||
|
||||
/* Free resources associated with old device channel. */
|
||||
for (i = 0; i < info->nr_ring_pages; i++) {
|
||||
if (rinfo->ring_ref[i] != GRANT_INVALID_REF) {
|
||||
gnttab_end_foreign_access(rinfo->ring_ref[i], 0);
|
||||
rinfo->ring_ref[i] = GRANT_INVALID_REF;
|
||||
}
|
||||
}
|
||||
free_pages_exact(rinfo->ring.sring,
|
||||
info->nr_ring_pages * XEN_PAGE_SIZE);
|
||||
rinfo->ring.sring = NULL;
|
||||
xenbus_teardown_ring((void **)&rinfo->ring.sring, info->nr_ring_pages,
|
||||
rinfo->ring_ref);
|
||||
|
||||
if (rinfo->irq)
|
||||
unbind_from_irqhandler(rinfo->irq, rinfo);
|
||||
|
@ -1475,7 +1466,7 @@ static int blkif_completion(unsigned long *id,
|
|||
* to the tail of the list, so it will not be picked
|
||||
* again unless we run out of persistent grants.
|
||||
*/
|
||||
s->grants_used[i]->gref = GRANT_INVALID_REF;
|
||||
s->grants_used[i]->gref = INVALID_GRANT_REF;
|
||||
list_add_tail(&s->grants_used[i]->node, &rinfo->grants);
|
||||
}
|
||||
}
|
||||
|
@ -1500,7 +1491,7 @@ static int blkif_completion(unsigned long *id,
|
|||
indirect_page = s->indirect_grants[i]->page;
|
||||
list_add(&indirect_page->lru, &rinfo->indirect_pages);
|
||||
}
|
||||
s->indirect_grants[i]->gref = GRANT_INVALID_REF;
|
||||
s->indirect_grants[i]->gref = INVALID_GRANT_REF;
|
||||
list_add_tail(&s->indirect_grants[i]->node, &rinfo->grants);
|
||||
}
|
||||
}
|
||||
|
@ -1681,30 +1672,16 @@ static int setup_blkring(struct xenbus_device *dev,
|
|||
struct blkfront_ring_info *rinfo)
|
||||
{
|
||||
struct blkif_sring *sring;
|
||||
int err, i;
|
||||
int err;
|
||||
struct blkfront_info *info = rinfo->dev_info;
|
||||
unsigned long ring_size = info->nr_ring_pages * XEN_PAGE_SIZE;
|
||||
grant_ref_t gref[XENBUS_MAX_RING_GRANTS];
|
||||
|
||||
for (i = 0; i < info->nr_ring_pages; i++)
|
||||
rinfo->ring_ref[i] = GRANT_INVALID_REF;
|
||||
|
||||
sring = alloc_pages_exact(ring_size, GFP_NOIO);
|
||||
if (!sring) {
|
||||
xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring");
|
||||
return -ENOMEM;
|
||||
}
|
||||
SHARED_RING_INIT(sring);
|
||||
FRONT_RING_INIT(&rinfo->ring, sring, ring_size);
|
||||
|
||||
err = xenbus_grant_ring(dev, rinfo->ring.sring, info->nr_ring_pages, gref);
|
||||
if (err < 0) {
|
||||
free_pages_exact(sring, ring_size);
|
||||
rinfo->ring.sring = NULL;
|
||||
err = xenbus_setup_ring(dev, GFP_NOIO, (void **)&sring,
|
||||
info->nr_ring_pages, rinfo->ring_ref);
|
||||
if (err)
|
||||
goto fail;
|
||||
}
|
||||
for (i = 0; i < info->nr_ring_pages; i++)
|
||||
rinfo->ring_ref[i] = gref[i];
|
||||
|
||||
XEN_FRONT_RING_INIT(&rinfo->ring, sring, ring_size);
|
||||
|
||||
err = xenbus_alloc_evtchn(dev, &rinfo->evtchn);
|
||||
if (err)
|
||||
|
@ -2544,13 +2521,13 @@ static void purge_persistent_grants(struct blkfront_info *info)
|
|||
|
||||
list_for_each_entry_safe(gnt_list_entry, tmp, &rinfo->grants,
|
||||
node) {
|
||||
if (gnt_list_entry->gref == GRANT_INVALID_REF ||
|
||||
if (gnt_list_entry->gref == INVALID_GRANT_REF ||
|
||||
!gnttab_try_end_foreign_access(gnt_list_entry->gref))
|
||||
continue;
|
||||
|
||||
list_del(&gnt_list_entry->node);
|
||||
rinfo->persistent_gnts_c--;
|
||||
gnt_list_entry->gref = GRANT_INVALID_REF;
|
||||
gnt_list_entry->gref = INVALID_GRANT_REF;
|
||||
list_add_tail(&gnt_list_entry->node, &grants);
|
||||
}
|
||||
|
||||
|
|
|
@ -253,20 +253,12 @@ static int setup_ring(struct xenbus_device *dev, struct tpm_private *priv)
|
|||
struct xenbus_transaction xbt;
|
||||
const char *message = NULL;
|
||||
int rv;
|
||||
grant_ref_t gref;
|
||||
|
||||
priv->shr = (void *)__get_free_page(GFP_KERNEL|__GFP_ZERO);
|
||||
if (!priv->shr) {
|
||||
xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
rv = xenbus_grant_ring(dev, priv->shr, 1, &gref);
|
||||
rv = xenbus_setup_ring(dev, GFP_KERNEL, (void **)&priv->shr, 1,
|
||||
&priv->ring_ref);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
|
||||
priv->ring_ref = gref;
|
||||
|
||||
rv = xenbus_alloc_evtchn(dev, &priv->evtchn);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
@ -331,11 +323,7 @@ static void ring_free(struct tpm_private *priv)
|
|||
if (!priv)
|
||||
return;
|
||||
|
||||
if (priv->ring_ref)
|
||||
gnttab_end_foreign_access(priv->ring_ref,
|
||||
(unsigned long)priv->shr);
|
||||
else
|
||||
free_page((unsigned long)priv->shr);
|
||||
xenbus_teardown_ring((void **)&priv->shr, 1, &priv->ring_ref);
|
||||
|
||||
if (priv->irq)
|
||||
unbind_from_irqhandler(priv->irq, priv);
|
||||
|
|
|
@ -80,15 +80,6 @@ struct drm_pending_vblank_event;
|
|||
/* timeout in ms to wait for backend to respond */
|
||||
#define XEN_DRM_FRONT_WAIT_BACK_MS 3000
|
||||
|
||||
#ifndef GRANT_INVALID_REF
|
||||
/*
|
||||
* Note on usage of grant reference 0 as invalid grant reference:
|
||||
* grant reference 0 is valid, but never exposed to a PV driver,
|
||||
* because of the fact it is already in use/reserved by the PV console.
|
||||
*/
|
||||
#define GRANT_INVALID_REF 0
|
||||
#endif
|
||||
|
||||
struct xen_drm_front_info {
|
||||
struct xenbus_device *xb_dev;
|
||||
struct xen_drm_front_drm_info *drm_info;
|
||||
|
|
|
@ -123,12 +123,12 @@ out:
|
|||
static void evtchnl_free(struct xen_drm_front_info *front_info,
|
||||
struct xen_drm_front_evtchnl *evtchnl)
|
||||
{
|
||||
unsigned long page = 0;
|
||||
void *page = NULL;
|
||||
|
||||
if (evtchnl->type == EVTCHNL_TYPE_REQ)
|
||||
page = (unsigned long)evtchnl->u.req.ring.sring;
|
||||
page = evtchnl->u.req.ring.sring;
|
||||
else if (evtchnl->type == EVTCHNL_TYPE_EVT)
|
||||
page = (unsigned long)evtchnl->u.evt.page;
|
||||
page = evtchnl->u.evt.page;
|
||||
if (!page)
|
||||
return;
|
||||
|
||||
|
@ -147,8 +147,7 @@ static void evtchnl_free(struct xen_drm_front_info *front_info,
|
|||
xenbus_free_evtchn(front_info->xb_dev, evtchnl->port);
|
||||
|
||||
/* end access and free the page */
|
||||
if (evtchnl->gref != GRANT_INVALID_REF)
|
||||
gnttab_end_foreign_access(evtchnl->gref, page);
|
||||
xenbus_teardown_ring(&page, 1, &evtchnl->gref);
|
||||
|
||||
memset(evtchnl, 0, sizeof(*evtchnl));
|
||||
}
|
||||
|
@ -158,8 +157,7 @@ static int evtchnl_alloc(struct xen_drm_front_info *front_info, int index,
|
|||
enum xen_drm_front_evtchnl_type type)
|
||||
{
|
||||
struct xenbus_device *xb_dev = front_info->xb_dev;
|
||||
unsigned long page;
|
||||
grant_ref_t gref;
|
||||
void *page;
|
||||
irq_handler_t handler;
|
||||
int ret;
|
||||
|
||||
|
@ -168,44 +166,25 @@ static int evtchnl_alloc(struct xen_drm_front_info *front_info, int index,
|
|||
evtchnl->index = index;
|
||||
evtchnl->front_info = front_info;
|
||||
evtchnl->state = EVTCHNL_STATE_DISCONNECTED;
|
||||
evtchnl->gref = GRANT_INVALID_REF;
|
||||
|
||||
page = get_zeroed_page(GFP_NOIO | __GFP_HIGH);
|
||||
if (!page) {
|
||||
ret = -ENOMEM;
|
||||
ret = xenbus_setup_ring(xb_dev, GFP_NOIO | __GFP_HIGH, &page,
|
||||
1, &evtchnl->gref);
|
||||
if (ret)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (type == EVTCHNL_TYPE_REQ) {
|
||||
struct xen_displif_sring *sring;
|
||||
|
||||
init_completion(&evtchnl->u.req.completion);
|
||||
mutex_init(&evtchnl->u.req.req_io_lock);
|
||||
sring = (struct xen_displif_sring *)page;
|
||||
SHARED_RING_INIT(sring);
|
||||
FRONT_RING_INIT(&evtchnl->u.req.ring, sring, XEN_PAGE_SIZE);
|
||||
|
||||
ret = xenbus_grant_ring(xb_dev, sring, 1, &gref);
|
||||
if (ret < 0) {
|
||||
evtchnl->u.req.ring.sring = NULL;
|
||||
free_page(page);
|
||||
goto fail;
|
||||
}
|
||||
sring = page;
|
||||
XEN_FRONT_RING_INIT(&evtchnl->u.req.ring, sring, XEN_PAGE_SIZE);
|
||||
|
||||
handler = evtchnl_interrupt_ctrl;
|
||||
} else {
|
||||
ret = gnttab_grant_foreign_access(xb_dev->otherend_id,
|
||||
virt_to_gfn((void *)page), 0);
|
||||
if (ret < 0) {
|
||||
free_page(page);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
evtchnl->u.evt.page = (struct xendispl_event_page *)page;
|
||||
gref = ret;
|
||||
evtchnl->u.evt.page = page;
|
||||
handler = evtchnl_interrupt_evt;
|
||||
}
|
||||
evtchnl->gref = gref;
|
||||
|
||||
ret = xenbus_alloc_evtchn(xb_dev, &evtchnl->port);
|
||||
if (ret < 0)
|
||||
|
|
|
@ -78,8 +78,6 @@ struct netfront_cb {
|
|||
|
||||
#define RX_COPY_THRESHOLD 256
|
||||
|
||||
#define GRANT_INVALID_REF 0
|
||||
|
||||
#define NET_TX_RING_SIZE __CONST_RING_SIZE(xen_netif_tx, XEN_PAGE_SIZE)
|
||||
#define NET_RX_RING_SIZE __CONST_RING_SIZE(xen_netif_rx, XEN_PAGE_SIZE)
|
||||
|
||||
|
@ -224,7 +222,7 @@ static grant_ref_t xennet_get_rx_ref(struct netfront_queue *queue,
|
|||
{
|
||||
int i = xennet_rxidx(ri);
|
||||
grant_ref_t ref = queue->grant_rx_ref[i];
|
||||
queue->grant_rx_ref[i] = GRANT_INVALID_REF;
|
||||
queue->grant_rx_ref[i] = INVALID_GRANT_REF;
|
||||
return ref;
|
||||
}
|
||||
|
||||
|
@ -432,7 +430,7 @@ static bool xennet_tx_buf_gc(struct netfront_queue *queue)
|
|||
}
|
||||
gnttab_release_grant_reference(
|
||||
&queue->gref_tx_head, queue->grant_tx_ref[id]);
|
||||
queue->grant_tx_ref[id] = GRANT_INVALID_REF;
|
||||
queue->grant_tx_ref[id] = INVALID_GRANT_REF;
|
||||
queue->grant_tx_page[id] = NULL;
|
||||
add_id_to_list(&queue->tx_skb_freelist, queue->tx_link, id);
|
||||
dev_kfree_skb_irq(skb);
|
||||
|
@ -868,7 +866,7 @@ static void xennet_set_rx_rsp_cons(struct netfront_queue *queue, RING_IDX val)
|
|||
|
||||
spin_lock_irqsave(&queue->rx_cons_lock, flags);
|
||||
queue->rx.rsp_cons = val;
|
||||
queue->rx_rsp_unconsumed = RING_HAS_UNCONSUMED_RESPONSES(&queue->rx);
|
||||
queue->rx_rsp_unconsumed = XEN_RING_NR_UNCONSUMED_RESPONSES(&queue->rx);
|
||||
spin_unlock_irqrestore(&queue->rx_cons_lock, flags);
|
||||
}
|
||||
|
||||
|
@ -1021,7 +1019,7 @@ static int xennet_get_responses(struct netfront_queue *queue,
|
|||
* the backend driver. In future this should flag the bad
|
||||
* situation to the system controller to reboot the backend.
|
||||
*/
|
||||
if (ref == GRANT_INVALID_REF) {
|
||||
if (ref == INVALID_GRANT_REF) {
|
||||
if (net_ratelimit())
|
||||
dev_warn(dev, "Bad rx response id %d.\n",
|
||||
rx->id);
|
||||
|
@ -1390,7 +1388,7 @@ static void xennet_release_tx_bufs(struct netfront_queue *queue)
|
|||
gnttab_end_foreign_access(queue->grant_tx_ref[i],
|
||||
(unsigned long)page_address(queue->grant_tx_page[i]));
|
||||
queue->grant_tx_page[i] = NULL;
|
||||
queue->grant_tx_ref[i] = GRANT_INVALID_REF;
|
||||
queue->grant_tx_ref[i] = INVALID_GRANT_REF;
|
||||
add_id_to_list(&queue->tx_skb_freelist, queue->tx_link, i);
|
||||
dev_kfree_skb_irq(skb);
|
||||
}
|
||||
|
@ -1411,7 +1409,7 @@ static void xennet_release_rx_bufs(struct netfront_queue *queue)
|
|||
continue;
|
||||
|
||||
ref = queue->grant_rx_ref[id];
|
||||
if (ref == GRANT_INVALID_REF)
|
||||
if (ref == INVALID_GRANT_REF)
|
||||
continue;
|
||||
|
||||
page = skb_frag_page(&skb_shinfo(skb)->frags[0]);
|
||||
|
@ -1422,7 +1420,7 @@ static void xennet_release_rx_bufs(struct netfront_queue *queue)
|
|||
get_page(page);
|
||||
gnttab_end_foreign_access(ref,
|
||||
(unsigned long)page_address(page));
|
||||
queue->grant_rx_ref[id] = GRANT_INVALID_REF;
|
||||
queue->grant_rx_ref[id] = INVALID_GRANT_REF;
|
||||
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
@ -1500,7 +1498,7 @@ static bool xennet_handle_rx(struct netfront_queue *queue, unsigned int *eoi)
|
|||
return false;
|
||||
|
||||
spin_lock_irqsave(&queue->rx_cons_lock, flags);
|
||||
work_queued = RING_HAS_UNCONSUMED_RESPONSES(&queue->rx);
|
||||
work_queued = XEN_RING_NR_UNCONSUMED_RESPONSES(&queue->rx);
|
||||
if (work_queued > queue->rx_rsp_unconsumed) {
|
||||
queue->rx_rsp_unconsumed = work_queued;
|
||||
*eoi = 0;
|
||||
|
@ -1761,7 +1759,7 @@ static int netfront_probe(struct xenbus_device *dev,
|
|||
static void xennet_end_access(int ref, void *page)
|
||||
{
|
||||
/* This frees the page as a side-effect */
|
||||
if (ref != GRANT_INVALID_REF)
|
||||
if (ref != INVALID_GRANT_REF)
|
||||
gnttab_end_foreign_access(ref, (unsigned long)page);
|
||||
}
|
||||
|
||||
|
@ -1798,8 +1796,8 @@ static void xennet_disconnect_backend(struct netfront_info *info)
|
|||
xennet_end_access(queue->tx_ring_ref, queue->tx.sring);
|
||||
xennet_end_access(queue->rx_ring_ref, queue->rx.sring);
|
||||
|
||||
queue->tx_ring_ref = GRANT_INVALID_REF;
|
||||
queue->rx_ring_ref = GRANT_INVALID_REF;
|
||||
queue->tx_ring_ref = INVALID_GRANT_REF;
|
||||
queue->rx_ring_ref = INVALID_GRANT_REF;
|
||||
queue->tx.sring = NULL;
|
||||
queue->rx.sring = NULL;
|
||||
|
||||
|
@ -1923,42 +1921,27 @@ static int setup_netfront(struct xenbus_device *dev,
|
|||
struct netfront_queue *queue, unsigned int feature_split_evtchn)
|
||||
{
|
||||
struct xen_netif_tx_sring *txs;
|
||||
struct xen_netif_rx_sring *rxs = NULL;
|
||||
grant_ref_t gref;
|
||||
struct xen_netif_rx_sring *rxs;
|
||||
int err;
|
||||
|
||||
queue->tx_ring_ref = GRANT_INVALID_REF;
|
||||
queue->rx_ring_ref = GRANT_INVALID_REF;
|
||||
queue->tx_ring_ref = INVALID_GRANT_REF;
|
||||
queue->rx_ring_ref = INVALID_GRANT_REF;
|
||||
queue->rx.sring = NULL;
|
||||
queue->tx.sring = NULL;
|
||||
|
||||
txs = (struct xen_netif_tx_sring *)get_zeroed_page(GFP_NOIO | __GFP_HIGH);
|
||||
if (!txs) {
|
||||
err = -ENOMEM;
|
||||
xenbus_dev_fatal(dev, err, "allocating tx ring page");
|
||||
err = xenbus_setup_ring(dev, GFP_NOIO | __GFP_HIGH, (void **)&txs,
|
||||
1, &queue->tx_ring_ref);
|
||||
if (err)
|
||||
goto fail;
|
||||
}
|
||||
SHARED_RING_INIT(txs);
|
||||
FRONT_RING_INIT(&queue->tx, txs, XEN_PAGE_SIZE);
|
||||
|
||||
err = xenbus_grant_ring(dev, txs, 1, &gref);
|
||||
if (err < 0)
|
||||
goto fail;
|
||||
queue->tx_ring_ref = gref;
|
||||
XEN_FRONT_RING_INIT(&queue->tx, txs, XEN_PAGE_SIZE);
|
||||
|
||||
rxs = (struct xen_netif_rx_sring *)get_zeroed_page(GFP_NOIO | __GFP_HIGH);
|
||||
if (!rxs) {
|
||||
err = -ENOMEM;
|
||||
xenbus_dev_fatal(dev, err, "allocating rx ring page");
|
||||
err = xenbus_setup_ring(dev, GFP_NOIO | __GFP_HIGH, (void **)&rxs,
|
||||
1, &queue->rx_ring_ref);
|
||||
if (err)
|
||||
goto fail;
|
||||
}
|
||||
SHARED_RING_INIT(rxs);
|
||||
FRONT_RING_INIT(&queue->rx, rxs, XEN_PAGE_SIZE);
|
||||
|
||||
err = xenbus_grant_ring(dev, rxs, 1, &gref);
|
||||
if (err < 0)
|
||||
goto fail;
|
||||
queue->rx_ring_ref = gref;
|
||||
XEN_FRONT_RING_INIT(&queue->rx, rxs, XEN_PAGE_SIZE);
|
||||
|
||||
if (feature_split_evtchn)
|
||||
err = setup_netfront_split(queue);
|
||||
|
@ -1974,24 +1957,10 @@ static int setup_netfront(struct xenbus_device *dev,
|
|||
|
||||
return 0;
|
||||
|
||||
/* If we fail to setup netfront, it is safe to just revoke access to
|
||||
* granted pages because backend is not accessing it at this point.
|
||||
*/
|
||||
fail:
|
||||
if (queue->rx_ring_ref != GRANT_INVALID_REF) {
|
||||
gnttab_end_foreign_access(queue->rx_ring_ref,
|
||||
(unsigned long)rxs);
|
||||
queue->rx_ring_ref = GRANT_INVALID_REF;
|
||||
} else {
|
||||
free_page((unsigned long)rxs);
|
||||
}
|
||||
if (queue->tx_ring_ref != GRANT_INVALID_REF) {
|
||||
gnttab_end_foreign_access(queue->tx_ring_ref,
|
||||
(unsigned long)txs);
|
||||
queue->tx_ring_ref = GRANT_INVALID_REF;
|
||||
} else {
|
||||
free_page((unsigned long)txs);
|
||||
}
|
||||
xenbus_teardown_ring((void **)&queue->rx.sring, 1, &queue->rx_ring_ref);
|
||||
xenbus_teardown_ring((void **)&queue->tx.sring, 1, &queue->tx_ring_ref);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -2020,7 +1989,7 @@ static int xennet_init_queue(struct netfront_queue *queue)
|
|||
queue->tx_pend_queue = TX_LINK_NONE;
|
||||
for (i = 0; i < NET_TX_RING_SIZE; i++) {
|
||||
queue->tx_link[i] = i + 1;
|
||||
queue->grant_tx_ref[i] = GRANT_INVALID_REF;
|
||||
queue->grant_tx_ref[i] = INVALID_GRANT_REF;
|
||||
queue->grant_tx_page[i] = NULL;
|
||||
}
|
||||
queue->tx_link[NET_TX_RING_SIZE - 1] = TX_LINK_NONE;
|
||||
|
@ -2028,7 +1997,7 @@ static int xennet_init_queue(struct netfront_queue *queue)
|
|||
/* Clear out rx_skbs */
|
||||
for (i = 0; i < NET_RX_RING_SIZE; i++) {
|
||||
queue->rx_skbs[i] = NULL;
|
||||
queue->grant_rx_ref[i] = GRANT_INVALID_REF;
|
||||
queue->grant_rx_ref[i] = INVALID_GRANT_REF;
|
||||
}
|
||||
|
||||
/* A grant for every tx ring slot */
|
||||
|
|
|
@ -709,9 +709,8 @@ static struct pcifront_device *alloc_pdev(struct xenbus_device *xdev)
|
|||
if (pdev == NULL)
|
||||
goto out;
|
||||
|
||||
pdev->sh_info =
|
||||
(struct xen_pci_sharedinfo *)__get_free_page(GFP_KERNEL);
|
||||
if (pdev->sh_info == NULL) {
|
||||
if (xenbus_setup_ring(xdev, GFP_KERNEL, (void **)&pdev->sh_info, 1,
|
||||
&pdev->gnt_ref)) {
|
||||
kfree(pdev);
|
||||
pdev = NULL;
|
||||
goto out;
|
||||
|
@ -729,7 +728,6 @@ static struct pcifront_device *alloc_pdev(struct xenbus_device *xdev)
|
|||
spin_lock_init(&pdev->sh_info_lock);
|
||||
|
||||
pdev->evtchn = INVALID_EVTCHN;
|
||||
pdev->gnt_ref = INVALID_GRANT_REF;
|
||||
pdev->irq = -1;
|
||||
|
||||
INIT_WORK(&pdev->op_work, pcifront_do_aer);
|
||||
|
@ -754,11 +752,7 @@ static void free_pdev(struct pcifront_device *pdev)
|
|||
if (pdev->evtchn != INVALID_EVTCHN)
|
||||
xenbus_free_evtchn(pdev->xdev, pdev->evtchn);
|
||||
|
||||
if (pdev->gnt_ref != INVALID_GRANT_REF)
|
||||
gnttab_end_foreign_access(pdev->gnt_ref,
|
||||
(unsigned long)pdev->sh_info);
|
||||
else
|
||||
free_page((unsigned long)pdev->sh_info);
|
||||
xenbus_teardown_ring((void **)&pdev->sh_info, 1, &pdev->gnt_ref);
|
||||
|
||||
dev_set_drvdata(&pdev->xdev->dev, NULL);
|
||||
|
||||
|
@ -769,13 +763,6 @@ static int pcifront_publish_info(struct pcifront_device *pdev)
|
|||
{
|
||||
int err = 0;
|
||||
struct xenbus_transaction trans;
|
||||
grant_ref_t gref;
|
||||
|
||||
err = xenbus_grant_ring(pdev->xdev, pdev->sh_info, 1, &gref);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
pdev->gnt_ref = gref;
|
||||
|
||||
err = xenbus_alloc_evtchn(pdev->xdev, &pdev->evtchn);
|
||||
if (err)
|
||||
|
|
|
@ -58,9 +58,6 @@
|
|||
|
||||
#include <asm/xen/hypervisor.h>
|
||||
|
||||
|
||||
#define GRANT_INVALID_REF 0
|
||||
|
||||
#define VSCSIFRONT_OP_ADD_LUN 1
|
||||
#define VSCSIFRONT_OP_DEL_LUN 2
|
||||
#define VSCSIFRONT_OP_READD_LUN 3
|
||||
|
@ -83,6 +80,8 @@ struct vscsifrnt_shadow {
|
|||
uint16_t rqid;
|
||||
uint16_t ref_rqid;
|
||||
|
||||
bool inflight;
|
||||
|
||||
unsigned int nr_grants; /* number of grants in gref[] */
|
||||
struct scsiif_request_segment *sg; /* scatter/gather elements */
|
||||
struct scsiif_request_segment seg[VSCSIIF_SG_TABLESIZE];
|
||||
|
@ -104,7 +103,11 @@ struct vscsifrnt_info {
|
|||
struct xenbus_device *dev;
|
||||
|
||||
struct Scsi_Host *host;
|
||||
int host_active;
|
||||
enum {
|
||||
STATE_INACTIVE,
|
||||
STATE_ACTIVE,
|
||||
STATE_ERROR
|
||||
} host_active;
|
||||
|
||||
unsigned int evtchn;
|
||||
unsigned int irq;
|
||||
|
@ -217,6 +220,8 @@ static int scsifront_do_request(struct vscsifrnt_info *info,
|
|||
for (i = 0; i < (shadow->nr_segments & ~VSCSIIF_SG_GRANT); i++)
|
||||
ring_req->seg[i] = shadow->seg[i];
|
||||
|
||||
shadow->inflight = true;
|
||||
|
||||
RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(ring, notify);
|
||||
if (notify)
|
||||
notify_remote_via_irq(info->irq);
|
||||
|
@ -224,6 +229,13 @@ static int scsifront_do_request(struct vscsifrnt_info *info,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void scsifront_set_error(struct vscsifrnt_info *info, const char *msg)
|
||||
{
|
||||
shost_printk(KERN_ERR, info->host, KBUILD_MODNAME "%s\n"
|
||||
"Disabling device for further use\n", msg);
|
||||
info->host_active = STATE_ERROR;
|
||||
}
|
||||
|
||||
static void scsifront_gnttab_done(struct vscsifrnt_info *info,
|
||||
struct vscsifrnt_shadow *shadow)
|
||||
{
|
||||
|
@ -234,15 +246,64 @@ static void scsifront_gnttab_done(struct vscsifrnt_info *info,
|
|||
|
||||
for (i = 0; i < shadow->nr_grants; i++) {
|
||||
if (unlikely(!gnttab_try_end_foreign_access(shadow->gref[i]))) {
|
||||
shost_printk(KERN_ALERT, info->host, KBUILD_MODNAME
|
||||
"grant still in use by backend\n");
|
||||
BUG();
|
||||
scsifront_set_error(info, "grant still in use by backend");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
kfree(shadow->sg);
|
||||
}
|
||||
|
||||
static unsigned int scsifront_host_byte(int32_t rslt)
|
||||
{
|
||||
switch (XEN_VSCSIIF_RSLT_HOST(rslt)) {
|
||||
case XEN_VSCSIIF_RSLT_HOST_OK:
|
||||
return DID_OK;
|
||||
case XEN_VSCSIIF_RSLT_HOST_NO_CONNECT:
|
||||
return DID_NO_CONNECT;
|
||||
case XEN_VSCSIIF_RSLT_HOST_BUS_BUSY:
|
||||
return DID_BUS_BUSY;
|
||||
case XEN_VSCSIIF_RSLT_HOST_TIME_OUT:
|
||||
return DID_TIME_OUT;
|
||||
case XEN_VSCSIIF_RSLT_HOST_BAD_TARGET:
|
||||
return DID_BAD_TARGET;
|
||||
case XEN_VSCSIIF_RSLT_HOST_ABORT:
|
||||
return DID_ABORT;
|
||||
case XEN_VSCSIIF_RSLT_HOST_PARITY:
|
||||
return DID_PARITY;
|
||||
case XEN_VSCSIIF_RSLT_HOST_ERROR:
|
||||
return DID_ERROR;
|
||||
case XEN_VSCSIIF_RSLT_HOST_RESET:
|
||||
return DID_RESET;
|
||||
case XEN_VSCSIIF_RSLT_HOST_BAD_INTR:
|
||||
return DID_BAD_INTR;
|
||||
case XEN_VSCSIIF_RSLT_HOST_PASSTHROUGH:
|
||||
return DID_PASSTHROUGH;
|
||||
case XEN_VSCSIIF_RSLT_HOST_SOFT_ERROR:
|
||||
return DID_SOFT_ERROR;
|
||||
case XEN_VSCSIIF_RSLT_HOST_IMM_RETRY:
|
||||
return DID_IMM_RETRY;
|
||||
case XEN_VSCSIIF_RSLT_HOST_REQUEUE:
|
||||
return DID_REQUEUE;
|
||||
case XEN_VSCSIIF_RSLT_HOST_TRANSPORT_DISRUPTED:
|
||||
return DID_TRANSPORT_DISRUPTED;
|
||||
case XEN_VSCSIIF_RSLT_HOST_TRANSPORT_FAILFAST:
|
||||
return DID_TRANSPORT_FAILFAST;
|
||||
case XEN_VSCSIIF_RSLT_HOST_TARGET_FAILURE:
|
||||
return DID_TARGET_FAILURE;
|
||||
case XEN_VSCSIIF_RSLT_HOST_NEXUS_FAILURE:
|
||||
return DID_NEXUS_FAILURE;
|
||||
case XEN_VSCSIIF_RSLT_HOST_ALLOC_FAILURE:
|
||||
return DID_ALLOC_FAILURE;
|
||||
case XEN_VSCSIIF_RSLT_HOST_MEDIUM_ERROR:
|
||||
return DID_MEDIUM_ERROR;
|
||||
case XEN_VSCSIIF_RSLT_HOST_TRANSPORT_MARGINAL:
|
||||
return DID_TRANSPORT_MARGINAL;
|
||||
default:
|
||||
return DID_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
static void scsifront_cdb_cmd_done(struct vscsifrnt_info *info,
|
||||
struct vscsiif_response *ring_rsp)
|
||||
{
|
||||
|
@ -250,7 +311,6 @@ static void scsifront_cdb_cmd_done(struct vscsifrnt_info *info,
|
|||
struct scsi_cmnd *sc;
|
||||
uint32_t id;
|
||||
uint8_t sense_len;
|
||||
int result;
|
||||
|
||||
id = ring_rsp->rqid;
|
||||
shadow = info->shadow[id];
|
||||
|
@ -259,14 +319,12 @@ static void scsifront_cdb_cmd_done(struct vscsifrnt_info *info,
|
|||
BUG_ON(sc == NULL);
|
||||
|
||||
scsifront_gnttab_done(info, shadow);
|
||||
if (info->host_active == STATE_ERROR)
|
||||
return;
|
||||
scsifront_put_rqid(info, id);
|
||||
|
||||
result = ring_rsp->rslt;
|
||||
if (result >> 24)
|
||||
set_host_byte(sc, DID_ERROR);
|
||||
else
|
||||
set_host_byte(sc, host_byte(result));
|
||||
set_status_byte(sc, result & 0xff);
|
||||
set_host_byte(sc, scsifront_host_byte(ring_rsp->rslt));
|
||||
set_status_byte(sc, XEN_VSCSIIF_RSLT_STATUS(ring_rsp->rslt));
|
||||
scsi_set_resid(sc, ring_rsp->residual_len);
|
||||
|
||||
sense_len = min_t(uint8_t, VSCSIIF_SENSE_BUFFERSIZE,
|
||||
|
@ -290,7 +348,10 @@ static void scsifront_sync_cmd_done(struct vscsifrnt_info *info,
|
|||
shadow->wait_reset = 1;
|
||||
switch (shadow->rslt_reset) {
|
||||
case RSLT_RESET_WAITING:
|
||||
shadow->rslt_reset = ring_rsp->rslt;
|
||||
if (ring_rsp->rslt == XEN_VSCSIIF_RSLT_RESET_SUCCESS)
|
||||
shadow->rslt_reset = SUCCESS;
|
||||
else
|
||||
shadow->rslt_reset = FAILED;
|
||||
break;
|
||||
case RSLT_RESET_ERR:
|
||||
kick = _scsifront_put_rqid(info, id);
|
||||
|
@ -300,9 +361,7 @@ static void scsifront_sync_cmd_done(struct vscsifrnt_info *info,
|
|||
scsifront_wake_up(info);
|
||||
return;
|
||||
default:
|
||||
shost_printk(KERN_ERR, info->host, KBUILD_MODNAME
|
||||
"bad reset state %d, possibly leaking %u\n",
|
||||
shadow->rslt_reset, id);
|
||||
scsifront_set_error(info, "bad reset state");
|
||||
break;
|
||||
}
|
||||
spin_unlock_irqrestore(&info->shadow_lock, flags);
|
||||
|
@ -313,28 +372,41 @@ static void scsifront_sync_cmd_done(struct vscsifrnt_info *info,
|
|||
static void scsifront_do_response(struct vscsifrnt_info *info,
|
||||
struct vscsiif_response *ring_rsp)
|
||||
{
|
||||
if (WARN(ring_rsp->rqid >= VSCSIIF_MAX_REQS ||
|
||||
test_bit(ring_rsp->rqid, info->shadow_free_bitmap),
|
||||
"illegal rqid %u returned by backend!\n", ring_rsp->rqid))
|
||||
return;
|
||||
struct vscsifrnt_shadow *shadow;
|
||||
|
||||
if (info->shadow[ring_rsp->rqid]->act == VSCSIIF_ACT_SCSI_CDB)
|
||||
if (ring_rsp->rqid >= VSCSIIF_MAX_REQS ||
|
||||
!info->shadow[ring_rsp->rqid]->inflight) {
|
||||
scsifront_set_error(info, "illegal rqid returned by backend!");
|
||||
return;
|
||||
}
|
||||
shadow = info->shadow[ring_rsp->rqid];
|
||||
shadow->inflight = false;
|
||||
|
||||
if (shadow->act == VSCSIIF_ACT_SCSI_CDB)
|
||||
scsifront_cdb_cmd_done(info, ring_rsp);
|
||||
else
|
||||
scsifront_sync_cmd_done(info, ring_rsp);
|
||||
}
|
||||
|
||||
static int scsifront_ring_drain(struct vscsifrnt_info *info)
|
||||
static int scsifront_ring_drain(struct vscsifrnt_info *info,
|
||||
unsigned int *eoiflag)
|
||||
{
|
||||
struct vscsiif_response *ring_rsp;
|
||||
struct vscsiif_response ring_rsp;
|
||||
RING_IDX i, rp;
|
||||
int more_to_do = 0;
|
||||
|
||||
rp = info->ring.sring->rsp_prod;
|
||||
rmb(); /* ordering required respective to dom0 */
|
||||
rp = READ_ONCE(info->ring.sring->rsp_prod);
|
||||
virt_rmb(); /* ordering required respective to backend */
|
||||
if (RING_RESPONSE_PROD_OVERFLOW(&info->ring, rp)) {
|
||||
scsifront_set_error(info, "illegal number of responses");
|
||||
return 0;
|
||||
}
|
||||
for (i = info->ring.rsp_cons; i != rp; i++) {
|
||||
ring_rsp = RING_GET_RESPONSE(&info->ring, i);
|
||||
scsifront_do_response(info, ring_rsp);
|
||||
RING_COPY_RESPONSE(&info->ring, i, &ring_rsp);
|
||||
scsifront_do_response(info, &ring_rsp);
|
||||
if (info->host_active == STATE_ERROR)
|
||||
return 0;
|
||||
*eoiflag &= ~XEN_EOI_FLAG_SPURIOUS;
|
||||
}
|
||||
|
||||
info->ring.rsp_cons = i;
|
||||
|
@ -347,14 +419,15 @@ static int scsifront_ring_drain(struct vscsifrnt_info *info)
|
|||
return more_to_do;
|
||||
}
|
||||
|
||||
static int scsifront_cmd_done(struct vscsifrnt_info *info)
|
||||
static int scsifront_cmd_done(struct vscsifrnt_info *info,
|
||||
unsigned int *eoiflag)
|
||||
{
|
||||
int more_to_do;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(info->host->host_lock, flags);
|
||||
|
||||
more_to_do = scsifront_ring_drain(info);
|
||||
more_to_do = scsifront_ring_drain(info, eoiflag);
|
||||
|
||||
info->wait_ring_available = 0;
|
||||
|
||||
|
@ -368,20 +441,28 @@ static int scsifront_cmd_done(struct vscsifrnt_info *info)
|
|||
static irqreturn_t scsifront_irq_fn(int irq, void *dev_id)
|
||||
{
|
||||
struct vscsifrnt_info *info = dev_id;
|
||||
unsigned int eoiflag = XEN_EOI_FLAG_SPURIOUS;
|
||||
|
||||
while (scsifront_cmd_done(info))
|
||||
if (info->host_active == STATE_ERROR) {
|
||||
xen_irq_lateeoi(irq, XEN_EOI_FLAG_SPURIOUS);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
while (scsifront_cmd_done(info, &eoiflag))
|
||||
/* Yield point for this unbounded loop. */
|
||||
cond_resched();
|
||||
|
||||
xen_irq_lateeoi(irq, eoiflag);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void scsifront_finish_all(struct vscsifrnt_info *info)
|
||||
{
|
||||
unsigned i;
|
||||
unsigned int i, dummy;
|
||||
struct vscsiif_response resp;
|
||||
|
||||
scsifront_ring_drain(info);
|
||||
scsifront_ring_drain(info, &dummy);
|
||||
|
||||
for (i = 0; i < VSCSIIF_MAX_REQS; i++) {
|
||||
if (test_bit(i, info->shadow_free_bitmap))
|
||||
|
@ -538,6 +619,9 @@ static int scsifront_queuecommand(struct Scsi_Host *shost,
|
|||
unsigned long flags;
|
||||
int err;
|
||||
|
||||
if (info->host_active == STATE_ERROR)
|
||||
return SCSI_MLQUEUE_HOST_BUSY;
|
||||
|
||||
sc->result = 0;
|
||||
|
||||
shadow->sc = sc;
|
||||
|
@ -590,6 +674,9 @@ static int scsifront_action_handler(struct scsi_cmnd *sc, uint8_t act)
|
|||
struct vscsifrnt_shadow *shadow, *s = scsi_cmd_priv(sc);
|
||||
int err = 0;
|
||||
|
||||
if (info->host_active == STATE_ERROR)
|
||||
return FAILED;
|
||||
|
||||
shadow = kzalloc(sizeof(*shadow), GFP_NOIO);
|
||||
if (!shadow)
|
||||
return FAILED;
|
||||
|
@ -661,6 +748,9 @@ static int scsifront_sdev_configure(struct scsi_device *sdev)
|
|||
struct vscsifrnt_info *info = shost_priv(sdev->host);
|
||||
int err;
|
||||
|
||||
if (info->host_active == STATE_ERROR)
|
||||
return -EIO;
|
||||
|
||||
if (info && current == info->curr) {
|
||||
err = xenbus_printf(XBT_NIL, info->dev->nodename,
|
||||
info->dev_state_path, "%d", XenbusStateConnected);
|
||||
|
@ -708,27 +798,15 @@ static int scsifront_alloc_ring(struct vscsifrnt_info *info)
|
|||
{
|
||||
struct xenbus_device *dev = info->dev;
|
||||
struct vscsiif_sring *sring;
|
||||
grant_ref_t gref;
|
||||
int err = -ENOMEM;
|
||||
int err;
|
||||
|
||||
/***** Frontend to Backend ring start *****/
|
||||
sring = (struct vscsiif_sring *)__get_free_page(GFP_KERNEL);
|
||||
if (!sring) {
|
||||
xenbus_dev_fatal(dev, err,
|
||||
"fail to allocate shared ring (Front to Back)");
|
||||
err = xenbus_setup_ring(dev, GFP_KERNEL, (void **)&sring, 1,
|
||||
&info->ring_ref);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
SHARED_RING_INIT(sring);
|
||||
FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE);
|
||||
|
||||
err = xenbus_grant_ring(dev, sring, 1, &gref);
|
||||
if (err < 0) {
|
||||
free_page((unsigned long)sring);
|
||||
xenbus_dev_fatal(dev, err,
|
||||
"fail to grant shared ring (Front to Back)");
|
||||
return err;
|
||||
}
|
||||
info->ring_ref = gref;
|
||||
XEN_FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE);
|
||||
|
||||
err = xenbus_alloc_evtchn(dev, &info->evtchn);
|
||||
if (err) {
|
||||
|
@ -736,7 +814,7 @@ static int scsifront_alloc_ring(struct vscsifrnt_info *info)
|
|||
goto free_gnttab;
|
||||
}
|
||||
|
||||
err = bind_evtchn_to_irq(info->evtchn);
|
||||
err = bind_evtchn_to_irq_lateeoi(info->evtchn);
|
||||
if (err <= 0) {
|
||||
xenbus_dev_fatal(dev, err, "bind_evtchn_to_irq");
|
||||
goto free_gnttab;
|
||||
|
@ -757,8 +835,7 @@ static int scsifront_alloc_ring(struct vscsifrnt_info *info)
|
|||
free_irq:
|
||||
unbind_from_irqhandler(info->irq, info);
|
||||
free_gnttab:
|
||||
gnttab_end_foreign_access(info->ring_ref,
|
||||
(unsigned long)info->ring.sring);
|
||||
xenbus_teardown_ring((void **)&sring, 1, &info->ring_ref);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -766,8 +843,7 @@ free_gnttab:
|
|||
static void scsifront_free_ring(struct vscsifrnt_info *info)
|
||||
{
|
||||
unbind_from_irqhandler(info->irq, info);
|
||||
gnttab_end_foreign_access(info->ring_ref,
|
||||
(unsigned long)info->ring.sring);
|
||||
xenbus_teardown_ring((void **)&info->ring.sring, 1, &info->ring_ref);
|
||||
}
|
||||
|
||||
static int scsifront_init_ring(struct vscsifrnt_info *info)
|
||||
|
@ -866,7 +942,7 @@ static int scsifront_probe(struct xenbus_device *dev,
|
|||
goto free_sring;
|
||||
}
|
||||
info->host = host;
|
||||
info->host_active = 1;
|
||||
info->host_active = STATE_ACTIVE;
|
||||
|
||||
xenbus_switch_state(dev, XenbusStateInitialised);
|
||||
|
||||
|
@ -934,10 +1010,10 @@ static int scsifront_remove(struct xenbus_device *dev)
|
|||
pr_debug("%s: %s removed\n", __func__, dev->nodename);
|
||||
|
||||
mutex_lock(&scsifront_mutex);
|
||||
if (info->host_active) {
|
||||
if (info->host_active != STATE_INACTIVE) {
|
||||
/* Scsi_host not yet removed */
|
||||
scsi_remove_host(info->host);
|
||||
info->host_active = 0;
|
||||
info->host_active = STATE_INACTIVE;
|
||||
}
|
||||
mutex_unlock(&scsifront_mutex);
|
||||
|
||||
|
@ -961,9 +1037,9 @@ static void scsifront_disconnect(struct vscsifrnt_info *info)
|
|||
*/
|
||||
|
||||
mutex_lock(&scsifront_mutex);
|
||||
if (info->host_active) {
|
||||
if (info->host_active != STATE_INACTIVE) {
|
||||
scsi_remove_host(host);
|
||||
info->host_active = 0;
|
||||
info->host_active = STATE_INACTIVE;
|
||||
}
|
||||
mutex_unlock(&scsifront_mutex);
|
||||
|
||||
|
@ -981,6 +1057,9 @@ static void scsifront_do_lun_hotplug(struct vscsifrnt_info *info, int op)
|
|||
unsigned int hst, chn, tgt, lun;
|
||||
struct scsi_device *sdev;
|
||||
|
||||
if (info->host_active == STATE_ERROR)
|
||||
return;
|
||||
|
||||
dir = xenbus_directory(XBT_NIL, dev->otherend, "vscsi-devs", &dir_n);
|
||||
if (IS_ERR(dir))
|
||||
return;
|
||||
|
|
|
@ -87,8 +87,6 @@ struct xenhcd_info {
|
|||
bool error;
|
||||
};
|
||||
|
||||
#define GRANT_INVALID_REF 0
|
||||
|
||||
#define XENHCD_RING_JIFFIES (HZ/200)
|
||||
#define XENHCD_SCAN_JIFFIES 1
|
||||
|
||||
|
@ -1100,19 +1098,10 @@ static void xenhcd_destroy_rings(struct xenhcd_info *info)
|
|||
unbind_from_irqhandler(info->irq, info);
|
||||
info->irq = 0;
|
||||
|
||||
if (info->urb_ring_ref != GRANT_INVALID_REF) {
|
||||
gnttab_end_foreign_access(info->urb_ring_ref,
|
||||
(unsigned long)info->urb_ring.sring);
|
||||
info->urb_ring_ref = GRANT_INVALID_REF;
|
||||
}
|
||||
info->urb_ring.sring = NULL;
|
||||
|
||||
if (info->conn_ring_ref != GRANT_INVALID_REF) {
|
||||
gnttab_end_foreign_access(info->conn_ring_ref,
|
||||
(unsigned long)info->conn_ring.sring);
|
||||
info->conn_ring_ref = GRANT_INVALID_REF;
|
||||
}
|
||||
info->conn_ring.sring = NULL;
|
||||
xenbus_teardown_ring((void **)&info->urb_ring.sring, 1,
|
||||
&info->urb_ring_ref);
|
||||
xenbus_teardown_ring((void **)&info->conn_ring.sring, 1,
|
||||
&info->conn_ring_ref);
|
||||
}
|
||||
|
||||
static int xenhcd_setup_rings(struct xenbus_device *dev,
|
||||
|
@ -1120,46 +1109,24 @@ static int xenhcd_setup_rings(struct xenbus_device *dev,
|
|||
{
|
||||
struct xenusb_urb_sring *urb_sring;
|
||||
struct xenusb_conn_sring *conn_sring;
|
||||
grant_ref_t gref;
|
||||
int err;
|
||||
|
||||
info->urb_ring_ref = GRANT_INVALID_REF;
|
||||
info->conn_ring_ref = GRANT_INVALID_REF;
|
||||
|
||||
urb_sring = (struct xenusb_urb_sring *)get_zeroed_page(
|
||||
GFP_NOIO | __GFP_HIGH);
|
||||
if (!urb_sring) {
|
||||
xenbus_dev_fatal(dev, -ENOMEM, "allocating urb ring");
|
||||
return -ENOMEM;
|
||||
info->conn_ring_ref = INVALID_GRANT_REF;
|
||||
err = xenbus_setup_ring(dev, GFP_NOIO | __GFP_HIGH,
|
||||
(void **)&urb_sring, 1, &info->urb_ring_ref);
|
||||
if (err) {
|
||||
xenbus_dev_fatal(dev, err, "allocating urb ring");
|
||||
return err;
|
||||
}
|
||||
SHARED_RING_INIT(urb_sring);
|
||||
FRONT_RING_INIT(&info->urb_ring, urb_sring, PAGE_SIZE);
|
||||
XEN_FRONT_RING_INIT(&info->urb_ring, urb_sring, PAGE_SIZE);
|
||||
|
||||
err = xenbus_grant_ring(dev, urb_sring, 1, &gref);
|
||||
if (err < 0) {
|
||||
free_page((unsigned long)urb_sring);
|
||||
info->urb_ring.sring = NULL;
|
||||
err = xenbus_setup_ring(dev, GFP_NOIO | __GFP_HIGH,
|
||||
(void **)&conn_sring, 1, &info->conn_ring_ref);
|
||||
if (err) {
|
||||
xenbus_dev_fatal(dev, err, "allocating conn ring");
|
||||
goto fail;
|
||||
}
|
||||
info->urb_ring_ref = gref;
|
||||
|
||||
conn_sring = (struct xenusb_conn_sring *)get_zeroed_page(
|
||||
GFP_NOIO | __GFP_HIGH);
|
||||
if (!conn_sring) {
|
||||
xenbus_dev_fatal(dev, -ENOMEM, "allocating conn ring");
|
||||
err = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
SHARED_RING_INIT(conn_sring);
|
||||
FRONT_RING_INIT(&info->conn_ring, conn_sring, PAGE_SIZE);
|
||||
|
||||
err = xenbus_grant_ring(dev, conn_sring, 1, &gref);
|
||||
if (err < 0) {
|
||||
free_page((unsigned long)conn_sring);
|
||||
info->conn_ring.sring = NULL;
|
||||
goto fail;
|
||||
}
|
||||
info->conn_ring_ref = gref;
|
||||
XEN_FRONT_RING_INIT(&info->conn_ring, conn_sring, PAGE_SIZE);
|
||||
|
||||
err = xenbus_alloc_evtchn(dev, &info->evtchn);
|
||||
if (err) {
|
||||
|
|
|
@ -24,15 +24,6 @@
|
|||
|
||||
MODULE_IMPORT_NS(DMA_BUF);
|
||||
|
||||
#ifndef GRANT_INVALID_REF
|
||||
/*
|
||||
* Note on usage of grant reference 0 as invalid grant reference:
|
||||
* grant reference 0 is valid, but never exposed to a driver,
|
||||
* because of the fact it is already in use/reserved by the PV console.
|
||||
*/
|
||||
#define GRANT_INVALID_REF 0
|
||||
#endif
|
||||
|
||||
struct gntdev_dmabuf {
|
||||
struct gntdev_dmabuf_priv *priv;
|
||||
struct dma_buf *dmabuf;
|
||||
|
@ -532,7 +523,7 @@ static void dmabuf_imp_end_foreign_access(u32 *refs, int count)
|
|||
int i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
if (refs[i] != GRANT_INVALID_REF)
|
||||
if (refs[i] != INVALID_GRANT_REF)
|
||||
gnttab_end_foreign_access(refs[i], 0UL);
|
||||
}
|
||||
|
||||
|
@ -567,7 +558,7 @@ static struct gntdev_dmabuf *dmabuf_imp_alloc_storage(int count)
|
|||
gntdev_dmabuf->nr_pages = count;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
gntdev_dmabuf->u.imp.refs[i] = GRANT_INVALID_REF;
|
||||
gntdev_dmabuf->u.imp.refs[i] = INVALID_GRANT_REF;
|
||||
|
||||
return gntdev_dmabuf;
|
||||
|
||||
|
|
|
@ -66,8 +66,6 @@
|
|||
|
||||
#include <asm/sync_bitops.h>
|
||||
|
||||
/* External tools reserve first few grant table entries. */
|
||||
#define NR_RESERVED_ENTRIES 8
|
||||
#define GNTTAB_LIST_END 0xffffffff
|
||||
|
||||
static grant_ref_t **gnttab_list;
|
||||
|
@ -209,6 +207,10 @@ static inline void check_free_callbacks(void)
|
|||
static void put_free_entry(grant_ref_t ref)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (unlikely(ref < GNTTAB_NR_RESERVED_ENTRIES))
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&gnttab_list_lock, flags);
|
||||
gnttab_entry(ref) = gnttab_free_head;
|
||||
gnttab_free_head = ref;
|
||||
|
@ -1465,12 +1467,12 @@ int gnttab_init(void)
|
|||
nr_init_grefs = nr_grant_frames *
|
||||
gnttab_interface->grefs_per_grant_frame;
|
||||
|
||||
for (i = NR_RESERVED_ENTRIES; i < nr_init_grefs - 1; i++)
|
||||
for (i = GNTTAB_NR_RESERVED_ENTRIES; i < nr_init_grefs - 1; i++)
|
||||
gnttab_entry(i) = i + 1;
|
||||
|
||||
gnttab_entry(nr_init_grefs - 1) = GNTTAB_LIST_END;
|
||||
gnttab_free_count = nr_init_grefs - NR_RESERVED_ENTRIES;
|
||||
gnttab_free_head = NR_RESERVED_ENTRIES;
|
||||
gnttab_free_count = nr_init_grefs - GNTTAB_NR_RESERVED_ENTRIES;
|
||||
gnttab_free_head = GNTTAB_NR_RESERVED_ENTRIES;
|
||||
|
||||
printk("Grant table initialized\n");
|
||||
return 0;
|
||||
|
|
|
@ -21,15 +21,6 @@
|
|||
|
||||
#include <xen/xen-front-pgdir-shbuf.h>
|
||||
|
||||
#ifndef GRANT_INVALID_REF
|
||||
/*
|
||||
* FIXME: usage of grant reference 0 as invalid grant reference:
|
||||
* grant reference 0 is valid, but never exposed to a PV driver,
|
||||
* because of the fact it is already in use/reserved by the PV console.
|
||||
*/
|
||||
#define GRANT_INVALID_REF 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This structure represents the structure of a shared page
|
||||
* that contains grant references to the pages of the shared
|
||||
|
@ -38,6 +29,7 @@
|
|||
*/
|
||||
struct xen_page_directory {
|
||||
grant_ref_t gref_dir_next_page;
|
||||
#define XEN_GREF_LIST_END 0
|
||||
grant_ref_t gref[1]; /* Variable length */
|
||||
};
|
||||
|
||||
|
@ -83,7 +75,7 @@ grant_ref_t
|
|||
xen_front_pgdir_shbuf_get_dir_start(struct xen_front_pgdir_shbuf *buf)
|
||||
{
|
||||
if (!buf->grefs)
|
||||
return GRANT_INVALID_REF;
|
||||
return INVALID_GRANT_REF;
|
||||
|
||||
return buf->grefs[0];
|
||||
}
|
||||
|
@ -142,7 +134,7 @@ void xen_front_pgdir_shbuf_free(struct xen_front_pgdir_shbuf *buf)
|
|||
int i;
|
||||
|
||||
for (i = 0; i < buf->num_grefs; i++)
|
||||
if (buf->grefs[i] != GRANT_INVALID_REF)
|
||||
if (buf->grefs[i] != INVALID_GRANT_REF)
|
||||
gnttab_end_foreign_access(buf->grefs[i], 0UL);
|
||||
}
|
||||
kfree(buf->grefs);
|
||||
|
@ -355,7 +347,7 @@ static void backend_fill_page_dir(struct xen_front_pgdir_shbuf *buf)
|
|||
}
|
||||
/* Last page must say there is no more pages. */
|
||||
page_dir = (struct xen_page_directory *)ptr;
|
||||
page_dir->gref_dir_next_page = GRANT_INVALID_REF;
|
||||
page_dir->gref_dir_next_page = XEN_GREF_LIST_END;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -384,7 +376,7 @@ static void guest_fill_page_dir(struct xen_front_pgdir_shbuf *buf)
|
|||
|
||||
if (grefs_left <= XEN_NUM_GREFS_PER_PAGE) {
|
||||
to_copy = grefs_left;
|
||||
page_dir->gref_dir_next_page = GRANT_INVALID_REF;
|
||||
page_dir->gref_dir_next_page = XEN_GREF_LIST_END;
|
||||
} else {
|
||||
to_copy = XEN_NUM_GREFS_PER_PAGE;
|
||||
page_dir->gref_dir_next_page = buf->grefs[i + 1];
|
||||
|
|
|
@ -280,6 +280,82 @@ static void scsiback_free_translation_entry(struct kref *kref)
|
|||
kfree(entry);
|
||||
}
|
||||
|
||||
static int32_t scsiback_result(int32_t result)
|
||||
{
|
||||
int32_t host_status;
|
||||
|
||||
switch (XEN_VSCSIIF_RSLT_HOST(result)) {
|
||||
case DID_OK:
|
||||
host_status = XEN_VSCSIIF_RSLT_HOST_OK;
|
||||
break;
|
||||
case DID_NO_CONNECT:
|
||||
host_status = XEN_VSCSIIF_RSLT_HOST_NO_CONNECT;
|
||||
break;
|
||||
case DID_BUS_BUSY:
|
||||
host_status = XEN_VSCSIIF_RSLT_HOST_BUS_BUSY;
|
||||
break;
|
||||
case DID_TIME_OUT:
|
||||
host_status = XEN_VSCSIIF_RSLT_HOST_TIME_OUT;
|
||||
break;
|
||||
case DID_BAD_TARGET:
|
||||
host_status = XEN_VSCSIIF_RSLT_HOST_BAD_TARGET;
|
||||
break;
|
||||
case DID_ABORT:
|
||||
host_status = XEN_VSCSIIF_RSLT_HOST_ABORT;
|
||||
break;
|
||||
case DID_PARITY:
|
||||
host_status = XEN_VSCSIIF_RSLT_HOST_PARITY;
|
||||
break;
|
||||
case DID_ERROR:
|
||||
host_status = XEN_VSCSIIF_RSLT_HOST_ERROR;
|
||||
break;
|
||||
case DID_RESET:
|
||||
host_status = XEN_VSCSIIF_RSLT_HOST_RESET;
|
||||
break;
|
||||
case DID_BAD_INTR:
|
||||
host_status = XEN_VSCSIIF_RSLT_HOST_BAD_INTR;
|
||||
break;
|
||||
case DID_PASSTHROUGH:
|
||||
host_status = XEN_VSCSIIF_RSLT_HOST_PASSTHROUGH;
|
||||
break;
|
||||
case DID_SOFT_ERROR:
|
||||
host_status = XEN_VSCSIIF_RSLT_HOST_SOFT_ERROR;
|
||||
break;
|
||||
case DID_IMM_RETRY:
|
||||
host_status = XEN_VSCSIIF_RSLT_HOST_IMM_RETRY;
|
||||
break;
|
||||
case DID_REQUEUE:
|
||||
host_status = XEN_VSCSIIF_RSLT_HOST_REQUEUE;
|
||||
break;
|
||||
case DID_TRANSPORT_DISRUPTED:
|
||||
host_status = XEN_VSCSIIF_RSLT_HOST_TRANSPORT_DISRUPTED;
|
||||
break;
|
||||
case DID_TRANSPORT_FAILFAST:
|
||||
host_status = XEN_VSCSIIF_RSLT_HOST_TRANSPORT_FAILFAST;
|
||||
break;
|
||||
case DID_TARGET_FAILURE:
|
||||
host_status = XEN_VSCSIIF_RSLT_HOST_TARGET_FAILURE;
|
||||
break;
|
||||
case DID_NEXUS_FAILURE:
|
||||
host_status = XEN_VSCSIIF_RSLT_HOST_NEXUS_FAILURE;
|
||||
break;
|
||||
case DID_ALLOC_FAILURE:
|
||||
host_status = XEN_VSCSIIF_RSLT_HOST_ALLOC_FAILURE;
|
||||
break;
|
||||
case DID_MEDIUM_ERROR:
|
||||
host_status = XEN_VSCSIIF_RSLT_HOST_MEDIUM_ERROR;
|
||||
break;
|
||||
case DID_TRANSPORT_MARGINAL:
|
||||
host_status = XEN_VSCSIIF_RSLT_HOST_TRANSPORT_MARGINAL;
|
||||
break;
|
||||
default:
|
||||
host_status = XEN_VSCSIIF_RSLT_HOST_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
return (host_status << 16) | (result & 0x00ffff);
|
||||
}
|
||||
|
||||
static void scsiback_send_response(struct vscsibk_info *info,
|
||||
char *sense_buffer, int32_t result, uint32_t resid,
|
||||
uint16_t rqid)
|
||||
|
@ -295,7 +371,7 @@ static void scsiback_send_response(struct vscsibk_info *info,
|
|||
ring_res = RING_GET_RESPONSE(&info->ring, info->ring.rsp_prod_pvt);
|
||||
info->ring.rsp_prod_pvt++;
|
||||
|
||||
ring_res->rslt = result;
|
||||
ring_res->rslt = scsiback_result(result);
|
||||
ring_res->rqid = rqid;
|
||||
|
||||
if (sense_buffer != NULL &&
|
||||
|
@ -555,7 +631,7 @@ static void scsiback_device_action(struct vscsibk_pend *pending_req,
|
|||
struct scsiback_nexus *nexus = tpg->tpg_nexus;
|
||||
struct se_cmd *se_cmd = &pending_req->se_cmd;
|
||||
u64 unpacked_lun = pending_req->v2p->lun;
|
||||
int rc, err = FAILED;
|
||||
int rc, err = XEN_VSCSIIF_RSLT_RESET_FAILED;
|
||||
|
||||
init_completion(&pending_req->tmr_done);
|
||||
|
||||
|
@ -569,7 +645,7 @@ static void scsiback_device_action(struct vscsibk_pend *pending_req,
|
|||
wait_for_completion(&pending_req->tmr_done);
|
||||
|
||||
err = (se_cmd->se_tmr_req->response == TMR_FUNCTION_COMPLETE) ?
|
||||
SUCCESS : FAILED;
|
||||
XEN_VSCSIIF_RSLT_RESET_SUCCESS : XEN_VSCSIIF_RSLT_RESET_FAILED;
|
||||
|
||||
scsiback_do_resp_with_sense(NULL, err, 0, pending_req);
|
||||
transport_generic_free_cmd(&pending_req->se_cmd, 0);
|
||||
|
|
|
@ -363,50 +363,92 @@ static void xenbus_switch_fatal(struct xenbus_device *dev, int depth, int err,
|
|||
__xenbus_switch_state(dev, XenbusStateClosing, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* xenbus_grant_ring
|
||||
/*
|
||||
* xenbus_setup_ring
|
||||
* @dev: xenbus device
|
||||
* @vaddr: starting virtual address of the ring
|
||||
* @vaddr: pointer to starting virtual address of the ring
|
||||
* @nr_pages: number of pages to be granted
|
||||
* @grefs: grant reference array to be filled in
|
||||
*
|
||||
* Grant access to the given @vaddr to the peer of the given device.
|
||||
* Then fill in @grefs with grant references. Return 0 on success, or
|
||||
* -errno on error. On error, the device will switch to
|
||||
* XenbusStateClosing, and the error will be saved in the store.
|
||||
* Allocate physically contiguous pages for a shared ring buffer and grant it
|
||||
* to the peer of the given device. The ring buffer is initially filled with
|
||||
* zeroes. The virtual address of the ring is stored at @vaddr and the
|
||||
* grant references are stored in the @grefs array. In case of error @vaddr
|
||||
* will be set to NULL and @grefs will be filled with INVALID_GRANT_REF.
|
||||
*/
|
||||
int xenbus_grant_ring(struct xenbus_device *dev, void *vaddr,
|
||||
int xenbus_setup_ring(struct xenbus_device *dev, gfp_t gfp, void **vaddr,
|
||||
unsigned int nr_pages, grant_ref_t *grefs)
|
||||
{
|
||||
int err;
|
||||
unsigned int i;
|
||||
unsigned long ring_size = nr_pages * XEN_PAGE_SIZE;
|
||||
grant_ref_t gref_head;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
err = gnttab_alloc_grant_references(nr_pages, &gref_head);
|
||||
if (err) {
|
||||
xenbus_dev_fatal(dev, err, "granting access to ring page");
|
||||
return err;
|
||||
*vaddr = alloc_pages_exact(ring_size, gfp | __GFP_ZERO);
|
||||
if (!*vaddr) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = gnttab_alloc_grant_references(nr_pages, &gref_head);
|
||||
if (ret) {
|
||||
xenbus_dev_fatal(dev, ret, "granting access to %u ring pages",
|
||||
nr_pages);
|
||||
goto err;
|
||||
}
|
||||
|
||||
for (i = 0; i < nr_pages; i++) {
|
||||
unsigned long gfn;
|
||||
|
||||
if (is_vmalloc_addr(vaddr))
|
||||
gfn = pfn_to_gfn(vmalloc_to_pfn(vaddr));
|
||||
if (is_vmalloc_addr(*vaddr))
|
||||
gfn = pfn_to_gfn(vmalloc_to_pfn(vaddr[i]));
|
||||
else
|
||||
gfn = virt_to_gfn(vaddr);
|
||||
gfn = virt_to_gfn(vaddr[i]);
|
||||
|
||||
grefs[i] = gnttab_claim_grant_reference(&gref_head);
|
||||
gnttab_grant_foreign_access_ref(grefs[i], dev->otherend_id,
|
||||
gfn, 0);
|
||||
|
||||
vaddr = vaddr + XEN_PAGE_SIZE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xenbus_grant_ring);
|
||||
|
||||
err:
|
||||
if (*vaddr)
|
||||
free_pages_exact(*vaddr, ring_size);
|
||||
for (i = 0; i < nr_pages; i++)
|
||||
grefs[i] = INVALID_GRANT_REF;
|
||||
*vaddr = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xenbus_setup_ring);
|
||||
|
||||
/*
|
||||
* xenbus_teardown_ring
|
||||
* @vaddr: starting virtual address of the ring
|
||||
* @nr_pages: number of pages
|
||||
* @grefs: grant reference array
|
||||
*
|
||||
* Remove grants for the shared ring buffer and free the associated memory.
|
||||
* On return the grant reference array is filled with INVALID_GRANT_REF.
|
||||
*/
|
||||
void xenbus_teardown_ring(void **vaddr, unsigned int nr_pages,
|
||||
grant_ref_t *grefs)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < nr_pages; i++) {
|
||||
if (grefs[i] != INVALID_GRANT_REF) {
|
||||
gnttab_end_foreign_access(grefs[i], 0);
|
||||
grefs[i] = INVALID_GRANT_REF;
|
||||
}
|
||||
}
|
||||
|
||||
if (*vaddr)
|
||||
free_pages_exact(*vaddr, nr_pages * XEN_PAGE_SIZE);
|
||||
*vaddr = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xenbus_teardown_ring);
|
||||
|
||||
/**
|
||||
* Allocate an event channel for the given xenbus_device, assigning the newly
|
||||
|
|
|
@ -65,6 +65,7 @@
|
|||
#include "xenbus.h"
|
||||
|
||||
|
||||
static int xs_init_irq;
|
||||
int xen_store_evtchn;
|
||||
EXPORT_SYMBOL_GPL(xen_store_evtchn);
|
||||
|
||||
|
@ -750,6 +751,20 @@ static void xenbus_probe(void)
|
|||
{
|
||||
xenstored_ready = 1;
|
||||
|
||||
if (!xen_store_interface) {
|
||||
xen_store_interface = xen_remap(xen_store_gfn << XEN_PAGE_SHIFT,
|
||||
XEN_PAGE_SIZE);
|
||||
/*
|
||||
* Now it is safe to free the IRQ used for xenstore late
|
||||
* initialization. No need to unbind: it is about to be
|
||||
* bound again from xb_init_comms. Note that calling
|
||||
* unbind_from_irqhandler now would result in xen_evtchn_close()
|
||||
* being called and the event channel not being enabled again
|
||||
* afterwards, resulting in missed event notifications.
|
||||
*/
|
||||
free_irq(xs_init_irq, &xb_waitq);
|
||||
}
|
||||
|
||||
/*
|
||||
* In the HVM case, xenbus_init() deferred its call to
|
||||
* xs_init() in case callbacks were not operational yet.
|
||||
|
@ -798,20 +813,22 @@ static int __init xenbus_probe_initcall(void)
|
|||
{
|
||||
/*
|
||||
* Probe XenBus here in the XS_PV case, and also XS_HVM unless we
|
||||
* need to wait for the platform PCI device to come up.
|
||||
* need to wait for the platform PCI device to come up or
|
||||
* xen_store_interface is not ready.
|
||||
*/
|
||||
if (xen_store_domain_type == XS_PV ||
|
||||
(xen_store_domain_type == XS_HVM &&
|
||||
!xs_hvm_defer_init_for_callback()))
|
||||
!xs_hvm_defer_init_for_callback() &&
|
||||
xen_store_interface != NULL))
|
||||
xenbus_probe();
|
||||
|
||||
/*
|
||||
* For XS_LOCAL, spawn a thread which will wait for xenstored
|
||||
* or a xenstore-stubdom to be started, then probe. It will be
|
||||
* triggered when communication starts happening, by waiting
|
||||
* on xb_waitq.
|
||||
* For XS_LOCAL or when xen_store_interface is not ready, spawn a
|
||||
* thread which will wait for xenstored or a xenstore-stubdom to be
|
||||
* started, then probe. It will be triggered when communication
|
||||
* starts happening, by waiting on xb_waitq.
|
||||
*/
|
||||
if (xen_store_domain_type == XS_LOCAL) {
|
||||
if (xen_store_domain_type == XS_LOCAL || xen_store_interface == NULL) {
|
||||
struct task_struct *probe_task;
|
||||
|
||||
probe_task = kthread_run(xenbus_probe_thread, NULL,
|
||||
|
@ -907,10 +924,25 @@ static struct notifier_block xenbus_resume_nb = {
|
|||
.notifier_call = xenbus_resume_cb,
|
||||
};
|
||||
|
||||
static irqreturn_t xenbus_late_init(int irq, void *unused)
|
||||
{
|
||||
int err;
|
||||
uint64_t v = 0;
|
||||
|
||||
err = hvm_get_parameter(HVM_PARAM_STORE_PFN, &v);
|
||||
if (err || !v || !~v)
|
||||
return IRQ_HANDLED;
|
||||
xen_store_gfn = (unsigned long)v;
|
||||
|
||||
wake_up(&xb_waitq);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int __init xenbus_init(void)
|
||||
{
|
||||
int err;
|
||||
uint64_t v = 0;
|
||||
bool wait = false;
|
||||
xen_store_domain_type = XS_UNKNOWN;
|
||||
|
||||
if (!xen_domain())
|
||||
|
@ -957,25 +989,44 @@ static int __init xenbus_init(void)
|
|||
* been properly initialized. Instead of attempting to map a
|
||||
* wrong guest physical address return error.
|
||||
*
|
||||
* Also recognize all bits set as an invalid value.
|
||||
* Also recognize all bits set as an invalid/uninitialized value.
|
||||
*/
|
||||
if (!v || !~v) {
|
||||
if (!v) {
|
||||
err = -ENOENT;
|
||||
goto out_error;
|
||||
}
|
||||
/* Avoid truncation on 32-bit. */
|
||||
if (v == ~0ULL) {
|
||||
wait = true;
|
||||
} else {
|
||||
/* Avoid truncation on 32-bit. */
|
||||
#if BITS_PER_LONG == 32
|
||||
if (v > ULONG_MAX) {
|
||||
pr_err("%s: cannot handle HVM_PARAM_STORE_PFN=%llx > ULONG_MAX\n",
|
||||
__func__, v);
|
||||
err = -EINVAL;
|
||||
goto out_error;
|
||||
}
|
||||
if (v > ULONG_MAX) {
|
||||
pr_err("%s: cannot handle HVM_PARAM_STORE_PFN=%llx > ULONG_MAX\n",
|
||||
__func__, v);
|
||||
err = -EINVAL;
|
||||
goto out_error;
|
||||
}
|
||||
#endif
|
||||
xen_store_gfn = (unsigned long)v;
|
||||
xen_store_interface =
|
||||
xen_remap(xen_store_gfn << XEN_PAGE_SHIFT,
|
||||
XEN_PAGE_SIZE);
|
||||
xen_store_gfn = (unsigned long)v;
|
||||
xen_store_interface =
|
||||
xen_remap(xen_store_gfn << XEN_PAGE_SHIFT,
|
||||
XEN_PAGE_SIZE);
|
||||
if (xen_store_interface->connection != XENSTORE_CONNECTED)
|
||||
wait = true;
|
||||
}
|
||||
if (wait) {
|
||||
err = bind_evtchn_to_irqhandler(xen_store_evtchn,
|
||||
xenbus_late_init,
|
||||
0, "xenstore_late_init",
|
||||
&xb_waitq);
|
||||
if (err < 0) {
|
||||
pr_err("xenstore_late_init couldn't bind irq err=%d\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
|
||||
xs_init_irq = err;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
pr_warn("Xenstore state unknown\n");
|
||||
|
|
|
@ -57,8 +57,6 @@
|
|||
#define INVALID_GRANT_REF ((grant_ref_t)-1)
|
||||
#define INVALID_GRANT_HANDLE ((grant_handle_t)-1)
|
||||
|
||||
#define GNTTAB_RESERVED_XENSTORE 1
|
||||
|
||||
/* NR_GRANT_FRAMES must be less than or equal to that configured in Xen */
|
||||
#define NR_GRANT_FRAMES 4
|
||||
|
||||
|
|
|
@ -19,7 +19,8 @@
|
|||
|
||||
/* Some rough guidelines on accessing and updating grant-table entries
|
||||
* in a concurrency-safe manner. For more information, Linux contains a
|
||||
* reference implementation for guest OSes (arch/xen/kernel/grant_table.c).
|
||||
* reference implementation for guest OSes (drivers/xen/grant_table.c, see
|
||||
* http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=blob;f=drivers/xen/grant-table.c;hb=HEAD
|
||||
*
|
||||
* NB. WMB is a no-op on current-generation x86 processors. However, a
|
||||
* compiler barrier will still be required.
|
||||
|
@ -80,8 +81,9 @@ typedef uint32_t grant_ref_t;
|
|||
*/
|
||||
|
||||
/*
|
||||
* Version 1 of the grant table entry structure is maintained purely
|
||||
* for backwards compatibility. New guests should use version 2.
|
||||
* Version 1 of the grant table entry structure is maintained largely for
|
||||
* backwards compatibility. New guests are recommended to support using
|
||||
* version 2 to overcome version 1 limitations, but to default to version 1.
|
||||
*/
|
||||
struct grant_entry_v1 {
|
||||
/* GTF_xxx: various type and flag information. [XEN,GST] */
|
||||
|
@ -89,12 +91,21 @@ struct grant_entry_v1 {
|
|||
/* The domain being granted foreign privileges. [GST] */
|
||||
domid_t domid;
|
||||
/*
|
||||
* GTF_permit_access: Frame that @domid is allowed to map and access. [GST]
|
||||
* GTF_accept_transfer: Frame whose ownership transferred by @domid. [XEN]
|
||||
* GTF_permit_access: GFN that @domid is allowed to map and access. [GST]
|
||||
* GTF_accept_transfer: GFN that @domid is allowed to transfer into. [GST]
|
||||
* GTF_transfer_completed: MFN whose ownership transferred by @domid
|
||||
* (non-translated guests only). [XEN]
|
||||
*/
|
||||
uint32_t frame;
|
||||
};
|
||||
|
||||
/* The first few grant table entries will be preserved across grant table
|
||||
* version changes and may be pre-populated at domain creation by tools.
|
||||
*/
|
||||
#define GNTTAB_NR_RESERVED_ENTRIES 8
|
||||
#define GNTTAB_RESERVED_CONSOLE 0
|
||||
#define GNTTAB_RESERVED_XENSTORE 1
|
||||
|
||||
/*
|
||||
* Type of grant entry.
|
||||
* GTF_invalid: This grant entry grants no privileges.
|
||||
|
@ -111,10 +122,13 @@ struct grant_entry_v1 {
|
|||
#define GTF_type_mask (3U<<0)
|
||||
|
||||
/*
|
||||
* Subflags for GTF_permit_access.
|
||||
* Subflags for GTF_permit_access and GTF_transitive.
|
||||
* GTF_readonly: Restrict @domid to read-only mappings and accesses. [GST]
|
||||
* GTF_reading: Grant entry is currently mapped for reading by @domid. [XEN]
|
||||
* GTF_writing: Grant entry is currently mapped for writing by @domid. [XEN]
|
||||
* Further subflags for GTF_permit_access only.
|
||||
* GTF_PAT, GTF_PWT, GTF_PCD: (x86) cache attribute flags to be used for
|
||||
* mappings of the grant [GST]
|
||||
* GTF_sub_page: Grant access to only a subrange of the page. @domid
|
||||
* will only be allowed to copy from the grant, and not
|
||||
* map it. [GST]
|
||||
|
@ -125,6 +139,12 @@ struct grant_entry_v1 {
|
|||
#define GTF_reading (1U<<_GTF_reading)
|
||||
#define _GTF_writing (4)
|
||||
#define GTF_writing (1U<<_GTF_writing)
|
||||
#define _GTF_PWT (5)
|
||||
#define GTF_PWT (1U<<_GTF_PWT)
|
||||
#define _GTF_PCD (6)
|
||||
#define GTF_PCD (1U<<_GTF_PCD)
|
||||
#define _GTF_PAT (7)
|
||||
#define GTF_PAT (1U<<_GTF_PAT)
|
||||
#define _GTF_sub_page (8)
|
||||
#define GTF_sub_page (1U<<_GTF_sub_page)
|
||||
|
||||
|
@ -164,8 +184,7 @@ struct grant_entry_header {
|
|||
};
|
||||
|
||||
/*
|
||||
* Version 2 of the grant entry structure, here is a union because three
|
||||
* different types are suppotted: full_page, sub_page and transitive.
|
||||
* Version 2 of the grant entry structure.
|
||||
*/
|
||||
union grant_entry_v2 {
|
||||
struct grant_entry_header hdr;
|
||||
|
@ -180,9 +199,9 @@ union grant_entry_v2 {
|
|||
* field of the same name in the V1 entry structure.
|
||||
*/
|
||||
struct {
|
||||
struct grant_entry_header hdr;
|
||||
uint32_t pad0;
|
||||
uint64_t frame;
|
||||
struct grant_entry_header hdr;
|
||||
uint32_t pad0;
|
||||
uint64_t frame;
|
||||
} full_page;
|
||||
|
||||
/*
|
||||
|
@ -191,10 +210,10 @@ union grant_entry_v2 {
|
|||
* in frame @frame.
|
||||
*/
|
||||
struct {
|
||||
struct grant_entry_header hdr;
|
||||
uint16_t page_off;
|
||||
uint16_t length;
|
||||
uint64_t frame;
|
||||
struct grant_entry_header hdr;
|
||||
uint16_t page_off;
|
||||
uint16_t length;
|
||||
uint64_t frame;
|
||||
} sub_page;
|
||||
|
||||
/*
|
||||
|
@ -202,12 +221,15 @@ union grant_entry_v2 {
|
|||
* grant @gref in domain @trans_domid, as if it was the local
|
||||
* domain. Obviously, the transitive access must be compatible
|
||||
* with the original grant.
|
||||
*
|
||||
* The current version of Xen does not allow transitive grants
|
||||
* to be mapped.
|
||||
*/
|
||||
struct {
|
||||
struct grant_entry_header hdr;
|
||||
domid_t trans_domid;
|
||||
uint16_t pad0;
|
||||
grant_ref_t gref;
|
||||
struct grant_entry_header hdr;
|
||||
domid_t trans_domid;
|
||||
uint16_t pad0;
|
||||
grant_ref_t gref;
|
||||
} transitive;
|
||||
|
||||
uint32_t __spacer[4]; /* Pad to a power of two */
|
||||
|
@ -219,6 +241,21 @@ typedef uint16_t grant_status_t;
|
|||
* GRANT TABLE QUERIES AND USES
|
||||
*/
|
||||
|
||||
#define GNTTABOP_map_grant_ref 0
|
||||
#define GNTTABOP_unmap_grant_ref 1
|
||||
#define GNTTABOP_setup_table 2
|
||||
#define GNTTABOP_dump_table 3
|
||||
#define GNTTABOP_transfer 4
|
||||
#define GNTTABOP_copy 5
|
||||
#define GNTTABOP_query_size 6
|
||||
#define GNTTABOP_unmap_and_replace 7
|
||||
#define GNTTABOP_set_version 8
|
||||
#define GNTTABOP_get_status_frames 9
|
||||
#define GNTTABOP_get_version 10
|
||||
#define GNTTABOP_swap_grant_ref 11
|
||||
#define GNTTABOP_cache_flush 12
|
||||
/* ` } */
|
||||
|
||||
/*
|
||||
* Handle to track a mapping created via a grant reference.
|
||||
*/
|
||||
|
@ -227,7 +264,7 @@ typedef uint32_t grant_handle_t;
|
|||
/*
|
||||
* GNTTABOP_map_grant_ref: Map the grant entry (<dom>,<ref>) for access
|
||||
* by devices and/or host CPUs. If successful, <handle> is a tracking number
|
||||
* that must be presented later to destroy the mapping(s). On error, <handle>
|
||||
* that must be presented later to destroy the mapping(s). On error, <status>
|
||||
* is a negative status code.
|
||||
* NOTES:
|
||||
* 1. If GNTMAP_device_map is specified then <dev_bus_addr> is the address
|
||||
|
@ -241,7 +278,6 @@ typedef uint32_t grant_handle_t;
|
|||
* host mapping is destroyed by other means then it is *NOT* guaranteed
|
||||
* to be accounted to the correct grant reference!
|
||||
*/
|
||||
#define GNTTABOP_map_grant_ref 0
|
||||
struct gnttab_map_grant_ref {
|
||||
/* IN parameters. */
|
||||
uint64_t host_addr;
|
||||
|
@ -266,7 +302,6 @@ DEFINE_GUEST_HANDLE_STRUCT(gnttab_map_grant_ref);
|
|||
* 3. After executing a batch of unmaps, it is guaranteed that no stale
|
||||
* mappings will remain in the device or host TLBs.
|
||||
*/
|
||||
#define GNTTABOP_unmap_grant_ref 1
|
||||
struct gnttab_unmap_grant_ref {
|
||||
/* IN parameters. */
|
||||
uint64_t host_addr;
|
||||
|
@ -286,7 +321,6 @@ DEFINE_GUEST_HANDLE_STRUCT(gnttab_unmap_grant_ref);
|
|||
* 2. Only a sufficiently-privileged domain may specify <dom> != DOMID_SELF.
|
||||
* 3. Xen may not support more than a single grant-table page per domain.
|
||||
*/
|
||||
#define GNTTABOP_setup_table 2
|
||||
struct gnttab_setup_table {
|
||||
/* IN parameters. */
|
||||
domid_t dom;
|
||||
|
@ -301,7 +335,6 @@ DEFINE_GUEST_HANDLE_STRUCT(gnttab_setup_table);
|
|||
* GNTTABOP_dump_table: Dump the contents of the grant table to the
|
||||
* xen console. Debugging use only.
|
||||
*/
|
||||
#define GNTTABOP_dump_table 3
|
||||
struct gnttab_dump_table {
|
||||
/* IN parameters. */
|
||||
domid_t dom;
|
||||
|
@ -311,17 +344,17 @@ struct gnttab_dump_table {
|
|||
DEFINE_GUEST_HANDLE_STRUCT(gnttab_dump_table);
|
||||
|
||||
/*
|
||||
* GNTTABOP_transfer_grant_ref: Transfer <frame> to a foreign domain. The
|
||||
* foreign domain has previously registered its interest in the transfer via
|
||||
* <domid, ref>.
|
||||
* GNTTABOP_transfer: Transfer <frame> to a foreign domain. The foreign domain
|
||||
* has previously registered its interest in the transfer via <domid, ref>.
|
||||
*
|
||||
* Note that, even if the transfer fails, the specified page no longer belongs
|
||||
* to the calling domain *unless* the error is GNTST_bad_page.
|
||||
*
|
||||
* Note further that only PV guests can use this operation.
|
||||
*/
|
||||
#define GNTTABOP_transfer 4
|
||||
struct gnttab_transfer {
|
||||
/* IN parameters. */
|
||||
xen_pfn_t mfn;
|
||||
xen_pfn_t mfn;
|
||||
domid_t domid;
|
||||
grant_ref_t ref;
|
||||
/* OUT parameters. */
|
||||
|
@ -352,21 +385,20 @@ DEFINE_GUEST_HANDLE_STRUCT(gnttab_transfer);
|
|||
#define _GNTCOPY_dest_gref (1)
|
||||
#define GNTCOPY_dest_gref (1<<_GNTCOPY_dest_gref)
|
||||
|
||||
#define GNTTABOP_copy 5
|
||||
struct gnttab_copy {
|
||||
/* IN parameters. */
|
||||
struct {
|
||||
union {
|
||||
grant_ref_t ref;
|
||||
xen_pfn_t gmfn;
|
||||
} u;
|
||||
domid_t domid;
|
||||
uint16_t offset;
|
||||
} source, dest;
|
||||
uint16_t len;
|
||||
uint16_t flags; /* GNTCOPY_* */
|
||||
/* OUT parameters. */
|
||||
int16_t status;
|
||||
/* IN parameters. */
|
||||
struct gnttab_copy_ptr {
|
||||
union {
|
||||
grant_ref_t ref;
|
||||
xen_pfn_t gmfn;
|
||||
} u;
|
||||
domid_t domid;
|
||||
uint16_t offset;
|
||||
} source, dest;
|
||||
uint16_t len;
|
||||
uint16_t flags; /* GNTCOPY_* */
|
||||
/* OUT parameters. */
|
||||
int16_t status;
|
||||
};
|
||||
DEFINE_GUEST_HANDLE_STRUCT(gnttab_copy);
|
||||
|
||||
|
@ -377,7 +409,6 @@ DEFINE_GUEST_HANDLE_STRUCT(gnttab_copy);
|
|||
* 1. <dom> may be specified as DOMID_SELF.
|
||||
* 2. Only a sufficiently-privileged domain may specify <dom> != DOMID_SELF.
|
||||
*/
|
||||
#define GNTTABOP_query_size 6
|
||||
struct gnttab_query_size {
|
||||
/* IN parameters. */
|
||||
domid_t dom;
|
||||
|
@ -399,7 +430,6 @@ DEFINE_GUEST_HANDLE_STRUCT(gnttab_query_size);
|
|||
* 2. After executing a batch of unmaps, it is guaranteed that no stale
|
||||
* mappings will remain in the device or host TLBs.
|
||||
*/
|
||||
#define GNTTABOP_unmap_and_replace 7
|
||||
struct gnttab_unmap_and_replace {
|
||||
/* IN parameters. */
|
||||
uint64_t host_addr;
|
||||
|
@ -412,14 +442,12 @@ DEFINE_GUEST_HANDLE_STRUCT(gnttab_unmap_and_replace);
|
|||
|
||||
/*
|
||||
* GNTTABOP_set_version: Request a particular version of the grant
|
||||
* table shared table structure. This operation can only be performed
|
||||
* once in any given domain. It must be performed before any grants
|
||||
* are activated; otherwise, the domain will be stuck with version 1.
|
||||
* The only defined versions are 1 and 2.
|
||||
* table shared table structure. This operation may be used to toggle
|
||||
* between different versions, but must be performed while no grants
|
||||
* are active. The only defined versions are 1 and 2.
|
||||
*/
|
||||
#define GNTTABOP_set_version 8
|
||||
struct gnttab_set_version {
|
||||
/* IN parameters */
|
||||
/* IN/OUT parameters */
|
||||
uint32_t version;
|
||||
};
|
||||
DEFINE_GUEST_HANDLE_STRUCT(gnttab_set_version);
|
||||
|
@ -436,7 +464,6 @@ DEFINE_GUEST_HANDLE_STRUCT(gnttab_set_version);
|
|||
* 1. <dom> may be specified as DOMID_SELF.
|
||||
* 2. Only a sufficiently-privileged domain may specify <dom> != DOMID_SELF.
|
||||
*/
|
||||
#define GNTTABOP_get_status_frames 9
|
||||
struct gnttab_get_status_frames {
|
||||
/* IN parameters. */
|
||||
uint32_t nr_frames;
|
||||
|
@ -451,7 +478,6 @@ DEFINE_GUEST_HANDLE_STRUCT(gnttab_get_status_frames);
|
|||
* GNTTABOP_get_version: Get the grant table version which is in
|
||||
* effect for domain <dom>.
|
||||
*/
|
||||
#define GNTTABOP_get_version 10
|
||||
struct gnttab_get_version {
|
||||
/* IN parameters */
|
||||
domid_t dom;
|
||||
|
@ -461,27 +487,38 @@ struct gnttab_get_version {
|
|||
};
|
||||
DEFINE_GUEST_HANDLE_STRUCT(gnttab_get_version);
|
||||
|
||||
/*
|
||||
* GNTTABOP_swap_grant_ref: Swap the contents of two grant entries.
|
||||
*/
|
||||
struct gnttab_swap_grant_ref {
|
||||
/* IN parameters */
|
||||
grant_ref_t ref_a;
|
||||
grant_ref_t ref_b;
|
||||
/* OUT parameters */
|
||||
int16_t status; /* GNTST_* */
|
||||
};
|
||||
DEFINE_GUEST_HANDLE_STRUCT(gnttab_swap_grant_ref);
|
||||
|
||||
/*
|
||||
* Issue one or more cache maintenance operations on a portion of a
|
||||
* page granted to the calling domain by a foreign domain.
|
||||
*/
|
||||
#define GNTTABOP_cache_flush 12
|
||||
struct gnttab_cache_flush {
|
||||
union {
|
||||
uint64_t dev_bus_addr;
|
||||
grant_ref_t ref;
|
||||
} a;
|
||||
uint16_t offset; /* offset from start of grant */
|
||||
uint16_t length; /* size within the grant */
|
||||
#define GNTTAB_CACHE_CLEAN (1<<0)
|
||||
#define GNTTAB_CACHE_INVAL (1<<1)
|
||||
#define GNTTAB_CACHE_SOURCE_GREF (1<<31)
|
||||
uint16_t offset; /* offset from start of grant */
|
||||
uint16_t length; /* size within the grant */
|
||||
#define GNTTAB_CACHE_CLEAN (1u<<0)
|
||||
#define GNTTAB_CACHE_INVAL (1u<<1)
|
||||
#define GNTTAB_CACHE_SOURCE_GREF (1u<<31)
|
||||
uint32_t op;
|
||||
};
|
||||
DEFINE_GUEST_HANDLE_STRUCT(gnttab_cache_flush);
|
||||
|
||||
/*
|
||||
* Bitfield values for update_pin_status.flags.
|
||||
* Bitfield values for gnttab_map_grant_ref.flags.
|
||||
*/
|
||||
/* Map the grant entry for access by I/O devices. */
|
||||
#define _GNTMAP_device_map (0)
|
||||
|
@ -531,6 +568,7 @@ DEFINE_GUEST_HANDLE_STRUCT(gnttab_cache_flush);
|
|||
#define GNTST_bad_copy_arg (-10) /* copy arguments cross page boundary. */
|
||||
#define GNTST_address_too_big (-11) /* transfer page address too large. */
|
||||
#define GNTST_eagain (-12) /* Operation not done; try again. */
|
||||
#define GNTST_no_space (-13) /* Out of space (handles etc). */
|
||||
|
||||
#define GNTTABOP_error_msgs { \
|
||||
"okay", \
|
||||
|
@ -545,7 +583,8 @@ DEFINE_GUEST_HANDLE_STRUCT(gnttab_cache_flush);
|
|||
"bad page", \
|
||||
"copy arguments cross page boundary", \
|
||||
"page address size too large", \
|
||||
"operation not done; try again" \
|
||||
"operation not done; try again", \
|
||||
"out of space", \
|
||||
}
|
||||
|
||||
#endif /* __XEN_PUBLIC_GRANT_TABLE_H__ */
|
||||
|
|
|
@ -72,9 +72,8 @@ typedef unsigned int RING_IDX;
|
|||
* of the shared memory area (PAGE_SIZE, for instance). To initialise
|
||||
* the front half:
|
||||
*
|
||||
* mytag_front_ring_t front_ring;
|
||||
* SHARED_RING_INIT((mytag_sring_t *)shared_page);
|
||||
* FRONT_RING_INIT(&front_ring, (mytag_sring_t *)shared_page, PAGE_SIZE);
|
||||
* mytag_front_ring_t ring;
|
||||
* XEN_FRONT_RING_INIT(&ring, (mytag_sring_t *)shared_page, PAGE_SIZE);
|
||||
*
|
||||
* Initializing the back follows similarly (note that only the front
|
||||
* initializes the shared ring):
|
||||
|
@ -146,6 +145,11 @@ struct __name##_back_ring { \
|
|||
|
||||
#define FRONT_RING_INIT(_r, _s, __size) FRONT_RING_ATTACH(_r, _s, 0, __size)
|
||||
|
||||
#define XEN_FRONT_RING_INIT(r, s, size) do { \
|
||||
SHARED_RING_INIT(s); \
|
||||
FRONT_RING_INIT(r, s, size); \
|
||||
} while (0)
|
||||
|
||||
#define BACK_RING_ATTACH(_r, _s, _i, __size) do { \
|
||||
(_r)->rsp_prod_pvt = (_i); \
|
||||
(_r)->req_cons = (_i); \
|
||||
|
@ -170,16 +174,21 @@ struct __name##_back_ring { \
|
|||
(RING_FREE_REQUESTS(_r) == 0)
|
||||
|
||||
/* Test if there are outstanding messages to be processed on a ring. */
|
||||
#define RING_HAS_UNCONSUMED_RESPONSES(_r) \
|
||||
#define XEN_RING_NR_UNCONSUMED_RESPONSES(_r) \
|
||||
((_r)->sring->rsp_prod - (_r)->rsp_cons)
|
||||
|
||||
#define RING_HAS_UNCONSUMED_REQUESTS(_r) ({ \
|
||||
#define XEN_RING_NR_UNCONSUMED_REQUESTS(_r) ({ \
|
||||
unsigned int req = (_r)->sring->req_prod - (_r)->req_cons; \
|
||||
unsigned int rsp = RING_SIZE(_r) - \
|
||||
((_r)->req_cons - (_r)->rsp_prod_pvt); \
|
||||
req < rsp ? req : rsp; \
|
||||
})
|
||||
|
||||
#define RING_HAS_UNCONSUMED_RESPONSES(_r) \
|
||||
(!!XEN_RING_NR_UNCONSUMED_RESPONSES(_r))
|
||||
#define RING_HAS_UNCONSUMED_REQUESTS(_r) \
|
||||
(!!XEN_RING_NR_UNCONSUMED_REQUESTS(_r))
|
||||
|
||||
/* Direct access to individual ring elements, by index. */
|
||||
#define RING_GET_REQUEST(_r, _idx) \
|
||||
(&((_r)->sring->ring[((_idx) & (RING_SIZE(_r) - 1))].req))
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
*
|
||||
* A string specifying the backend device: either a 4-tuple "h:c:t:l"
|
||||
* (host, controller, target, lun, all integers), or a WWN (e.g.
|
||||
* "naa.60014054ac780582").
|
||||
* "naa.60014054ac780582:0").
|
||||
*
|
||||
* v-dev
|
||||
* Values: string
|
||||
|
@ -87,6 +87,75 @@
|
|||
* response structures.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Xenstore format in practice
|
||||
* ===========================
|
||||
*
|
||||
* The backend driver uses a single_host:many_devices notation to manage domU
|
||||
* devices. Everything is stored in /local/domain/<backend_domid>/backend/vscsi/.
|
||||
* The xenstore layout looks like this (dom0 is assumed to be the backend_domid):
|
||||
*
|
||||
* <domid>/<vhost>/feature-host = "0"
|
||||
* <domid>/<vhost>/frontend = "/local/domain/<domid>/device/vscsi/0"
|
||||
* <domid>/<vhost>/frontend-id = "<domid>"
|
||||
* <domid>/<vhost>/online = "1"
|
||||
* <domid>/<vhost>/state = "4"
|
||||
* <domid>/<vhost>/vscsi-devs/dev-0/p-dev = "8:0:2:1" or "naa.wwn:lun"
|
||||
* <domid>/<vhost>/vscsi-devs/dev-0/state = "4"
|
||||
* <domid>/<vhost>/vscsi-devs/dev-0/v-dev = "0:0:0:0"
|
||||
* <domid>/<vhost>/vscsi-devs/dev-1/p-dev = "8:0:2:2"
|
||||
* <domid>/<vhost>/vscsi-devs/dev-1/state = "4"
|
||||
* <domid>/<vhost>/vscsi-devs/dev-1/v-dev = "0:0:1:0"
|
||||
*
|
||||
* The frontend driver maintains its state in
|
||||
* /local/domain/<domid>/device/vscsi/.
|
||||
*
|
||||
* <vhost>/backend = "/local/domain/0/backend/vscsi/<domid>/<vhost>"
|
||||
* <vhost>/backend-id = "0"
|
||||
* <vhost>/event-channel = "20"
|
||||
* <vhost>/ring-ref = "43"
|
||||
* <vhost>/state = "4"
|
||||
* <vhost>/vscsi-devs/dev-0/state = "4"
|
||||
* <vhost>/vscsi-devs/dev-1/state = "4"
|
||||
*
|
||||
* In addition to the entries for backend and frontend these flags are stored
|
||||
* for the toolstack:
|
||||
*
|
||||
* <domid>/<vhost>/vscsi-devs/dev-1/p-devname = "/dev/$device"
|
||||
* <domid>/<vhost>/libxl_ctrl_index = "0"
|
||||
*
|
||||
*
|
||||
* Backend/frontend protocol
|
||||
* =========================
|
||||
*
|
||||
* To create a vhost along with a device:
|
||||
* <domid>/<vhost>/feature-host = "0"
|
||||
* <domid>/<vhost>/frontend = "/local/domain/<domid>/device/vscsi/0"
|
||||
* <domid>/<vhost>/frontend-id = "<domid>"
|
||||
* <domid>/<vhost>/online = "1"
|
||||
* <domid>/<vhost>/state = "1"
|
||||
* <domid>/<vhost>/vscsi-devs/dev-0/p-dev = "8:0:2:1"
|
||||
* <domid>/<vhost>/vscsi-devs/dev-0/state = "1"
|
||||
* <domid>/<vhost>/vscsi-devs/dev-0/v-dev = "0:0:0:0"
|
||||
* Wait for <domid>/<vhost>/state + <domid>/<vhost>/vscsi-devs/dev-0/state become 4
|
||||
*
|
||||
* To add another device to a vhost:
|
||||
* <domid>/<vhost>/state = "7"
|
||||
* <domid>/<vhost>/vscsi-devs/dev-1/p-dev = "8:0:2:2"
|
||||
* <domid>/<vhost>/vscsi-devs/dev-1/state = "1"
|
||||
* <domid>/<vhost>/vscsi-devs/dev-1/v-dev = "0:0:1:0"
|
||||
* Wait for <domid>/<vhost>/state + <domid>/<vhost>/vscsi-devs/dev-1/state become 4
|
||||
*
|
||||
* To remove a device from a vhost:
|
||||
* <domid>/<vhost>/state = "7"
|
||||
* <domid>/<vhost>/vscsi-devs/dev-1/state = "5"
|
||||
* Wait for <domid>/<vhost>/state to become 4
|
||||
* Wait for <domid>/<vhost>/vscsi-devs/dev-1/state become 6
|
||||
* Remove <domid>/<vhost>/vscsi-devs/dev-1/{state,p-dev,v-dev,p-devname}
|
||||
* Remove <domid>/<vhost>/vscsi-devs/dev-1/
|
||||
*
|
||||
*/
|
||||
|
||||
/* Requests from the frontend to the backend */
|
||||
|
||||
/*
|
||||
|
@ -117,7 +186,8 @@
|
|||
* (plus the set VSCSIIF_SG_GRANT bit), the number of scsiif_request_segment
|
||||
* elements referencing the target data buffers is calculated from the lengths
|
||||
* of the seg[] elements (the sum of all valid seg[].length divided by the
|
||||
* size of one scsiif_request_segment structure).
|
||||
* size of one scsiif_request_segment structure). The frontend may use a mix of
|
||||
* direct and indirect requests.
|
||||
*/
|
||||
#define VSCSIIF_ACT_SCSI_CDB 1
|
||||
|
||||
|
@ -154,12 +224,14 @@
|
|||
|
||||
/*
|
||||
* based on Linux kernel 2.6.18, still valid
|
||||
*
|
||||
* Changing these values requires support of multiple protocols via the rings
|
||||
* as "old clients" will blindly use these values and the resulting structure
|
||||
* sizes.
|
||||
*/
|
||||
#define VSCSIIF_MAX_COMMAND_SIZE 16
|
||||
#define VSCSIIF_SENSE_BUFFERSIZE 96
|
||||
#define VSCSIIF_PAGE_SIZE 4096
|
||||
|
||||
struct scsiif_request_segment {
|
||||
grant_ref_t gref;
|
||||
|
@ -167,7 +239,8 @@ struct scsiif_request_segment {
|
|||
uint16_t length;
|
||||
};
|
||||
|
||||
#define VSCSIIF_SG_PER_PAGE (PAGE_SIZE / sizeof(struct scsiif_request_segment))
|
||||
#define VSCSIIF_SG_PER_PAGE (VSCSIIF_PAGE_SIZE / \
|
||||
sizeof(struct scsiif_request_segment))
|
||||
|
||||
/* Size of one request is 252 bytes */
|
||||
struct vscsiif_request {
|
||||
|
@ -207,6 +280,58 @@ struct vscsiif_response {
|
|||
uint32_t reserved[36];
|
||||
};
|
||||
|
||||
/* SCSI I/O status from vscsiif_response->rslt */
|
||||
#define XEN_VSCSIIF_RSLT_STATUS(x) ((x) & 0x00ff)
|
||||
|
||||
/* Host I/O status from vscsiif_response->rslt */
|
||||
#define XEN_VSCSIIF_RSLT_HOST(x) (((x) & 0x00ff0000) >> 16)
|
||||
#define XEN_VSCSIIF_RSLT_HOST_OK 0
|
||||
/* Couldn't connect before timeout */
|
||||
#define XEN_VSCSIIF_RSLT_HOST_NO_CONNECT 1
|
||||
/* Bus busy through timeout */
|
||||
#define XEN_VSCSIIF_RSLT_HOST_BUS_BUSY 2
|
||||
/* Timed out for other reason */
|
||||
#define XEN_VSCSIIF_RSLT_HOST_TIME_OUT 3
|
||||
/* Bad target */
|
||||
#define XEN_VSCSIIF_RSLT_HOST_BAD_TARGET 4
|
||||
/* Abort for some other reason */
|
||||
#define XEN_VSCSIIF_RSLT_HOST_ABORT 5
|
||||
/* Parity error */
|
||||
#define XEN_VSCSIIF_RSLT_HOST_PARITY 6
|
||||
/* Internal error */
|
||||
#define XEN_VSCSIIF_RSLT_HOST_ERROR 7
|
||||
/* Reset by somebody */
|
||||
#define XEN_VSCSIIF_RSLT_HOST_RESET 8
|
||||
/* Unexpected interrupt */
|
||||
#define XEN_VSCSIIF_RSLT_HOST_BAD_INTR 9
|
||||
/* Force command past mid-layer */
|
||||
#define XEN_VSCSIIF_RSLT_HOST_PASSTHROUGH 10
|
||||
/* Retry requested */
|
||||
#define XEN_VSCSIIF_RSLT_HOST_SOFT_ERROR 11
|
||||
/* Hidden retry requested */
|
||||
#define XEN_VSCSIIF_RSLT_HOST_IMM_RETRY 12
|
||||
/* Requeue command requested */
|
||||
#define XEN_VSCSIIF_RSLT_HOST_REQUEUE 13
|
||||
/* Transport error disrupted I/O */
|
||||
#define XEN_VSCSIIF_RSLT_HOST_TRANSPORT_DISRUPTED 14
|
||||
/* Transport class fastfailed */
|
||||
#define XEN_VSCSIIF_RSLT_HOST_TRANSPORT_FAILFAST 15
|
||||
/* Permanent target failure */
|
||||
#define XEN_VSCSIIF_RSLT_HOST_TARGET_FAILURE 16
|
||||
/* Permanent nexus failure on path */
|
||||
#define XEN_VSCSIIF_RSLT_HOST_NEXUS_FAILURE 17
|
||||
/* Space allocation on device failed */
|
||||
#define XEN_VSCSIIF_RSLT_HOST_ALLOC_FAILURE 18
|
||||
/* Medium error */
|
||||
#define XEN_VSCSIIF_RSLT_HOST_MEDIUM_ERROR 19
|
||||
/* Transport marginal errors */
|
||||
#define XEN_VSCSIIF_RSLT_HOST_TRANSPORT_MARGINAL 20
|
||||
|
||||
/* Result values of reset operations */
|
||||
#define XEN_VSCSIIF_RSLT_RESET_SUCCESS 0x2002
|
||||
#define XEN_VSCSIIF_RSLT_RESET_FAILED 0x2003
|
||||
|
||||
DEFINE_RING_TYPES(vscsiif, struct vscsiif_request, struct vscsiif_response);
|
||||
|
||||
#endif /*__XEN__PUBLIC_IO_SCSI_H__*/
|
||||
|
||||
#endif /*__XEN__PUBLIC_IO_SCSI_H__*/
|
||||
|
|
|
@ -10,7 +10,8 @@
|
|||
|
||||
enum xsd_sockmsg_type
|
||||
{
|
||||
XS_DEBUG,
|
||||
XS_CONTROL,
|
||||
#define XS_DEBUG XS_CONTROL
|
||||
XS_DIRECTORY,
|
||||
XS_READ,
|
||||
XS_GET_PERMS,
|
||||
|
@ -30,8 +31,13 @@ enum xsd_sockmsg_type
|
|||
XS_IS_DOMAIN_INTRODUCED,
|
||||
XS_RESUME,
|
||||
XS_SET_TARGET,
|
||||
XS_RESTRICT,
|
||||
XS_RESET_WATCHES,
|
||||
/* XS_RESTRICT has been removed */
|
||||
XS_RESET_WATCHES = XS_SET_TARGET + 2,
|
||||
XS_DIRECTORY_PART,
|
||||
|
||||
XS_TYPE_COUNT, /* Number of valid types. */
|
||||
|
||||
XS_INVALID = 0xffff /* Guaranteed to remain an invalid type */
|
||||
};
|
||||
|
||||
#define XS_WRITE_NONE "NONE"
|
||||
|
@ -59,7 +65,8 @@ static struct xsd_errors xsd_errors[] __attribute__((unused)) = {
|
|||
XSD_ERROR(EROFS),
|
||||
XSD_ERROR(EBUSY),
|
||||
XSD_ERROR(EAGAIN),
|
||||
XSD_ERROR(EISCONN)
|
||||
XSD_ERROR(EISCONN),
|
||||
XSD_ERROR(E2BIG)
|
||||
};
|
||||
|
||||
struct xsd_sockmsg
|
||||
|
@ -87,9 +94,31 @@ struct xenstore_domain_interface {
|
|||
char rsp[XENSTORE_RING_SIZE]; /* Replies and async watch events. */
|
||||
XENSTORE_RING_IDX req_cons, req_prod;
|
||||
XENSTORE_RING_IDX rsp_cons, rsp_prod;
|
||||
uint32_t server_features; /* Bitmap of features supported by the server */
|
||||
uint32_t connection;
|
||||
uint32_t error;
|
||||
};
|
||||
|
||||
/* Violating this is very bad. See docs/misc/xenstore.txt. */
|
||||
#define XENSTORE_PAYLOAD_MAX 4096
|
||||
|
||||
/* Violating these just gets you an error back */
|
||||
#define XENSTORE_ABS_PATH_MAX 3072
|
||||
#define XENSTORE_REL_PATH_MAX 2048
|
||||
|
||||
/* The ability to reconnect a ring */
|
||||
#define XENSTORE_SERVER_FEATURE_RECONNECTION 1
|
||||
/* The presence of the "error" field in the ring page */
|
||||
#define XENSTORE_SERVER_FEATURE_ERROR 2
|
||||
|
||||
/* Valid values for the connection field */
|
||||
#define XENSTORE_CONNECTED 0 /* the steady-state */
|
||||
#define XENSTORE_RECONNECT 1 /* guest has initiated a reconnect */
|
||||
|
||||
/* Valid values for the error field */
|
||||
#define XENSTORE_ERROR_NONE 0 /* No error */
|
||||
#define XENSTORE_ERROR_COMM 1 /* Communication problem */
|
||||
#define XENSTORE_ERROR_RINGIDX 2 /* Invalid ring index */
|
||||
#define XENSTORE_ERROR_PROTO 3 /* Protocol violation (payload too long) */
|
||||
|
||||
#endif /* _XS_WIRE_H */
|
||||
|
|
|
@ -224,8 +224,10 @@ int xenbus_watch_pathfmt(struct xenbus_device *dev, struct xenbus_watch *watch,
|
|||
const char *pathfmt, ...);
|
||||
|
||||
int xenbus_switch_state(struct xenbus_device *dev, enum xenbus_state new_state);
|
||||
int xenbus_grant_ring(struct xenbus_device *dev, void *vaddr,
|
||||
int xenbus_setup_ring(struct xenbus_device *dev, gfp_t gfp, void **vaddr,
|
||||
unsigned int nr_pages, grant_ref_t *grefs);
|
||||
void xenbus_teardown_ring(void **vaddr, unsigned int nr_pages,
|
||||
grant_ref_t *grefs);
|
||||
int xenbus_map_ring_valloc(struct xenbus_device *dev, grant_ref_t *gnt_refs,
|
||||
unsigned int nr_grefs, void **vaddr);
|
||||
|
||||
|
|
|
@ -143,12 +143,12 @@ void xen_snd_front_evtchnl_flush(struct xen_snd_front_evtchnl *channel)
|
|||
static void evtchnl_free(struct xen_snd_front_info *front_info,
|
||||
struct xen_snd_front_evtchnl *channel)
|
||||
{
|
||||
unsigned long page = 0;
|
||||
void *page = NULL;
|
||||
|
||||
if (channel->type == EVTCHNL_TYPE_REQ)
|
||||
page = (unsigned long)channel->u.req.ring.sring;
|
||||
page = channel->u.req.ring.sring;
|
||||
else if (channel->type == EVTCHNL_TYPE_EVT)
|
||||
page = (unsigned long)channel->u.evt.page;
|
||||
page = channel->u.evt.page;
|
||||
|
||||
if (!page)
|
||||
return;
|
||||
|
@ -167,10 +167,7 @@ static void evtchnl_free(struct xen_snd_front_info *front_info,
|
|||
xenbus_free_evtchn(front_info->xb_dev, channel->port);
|
||||
|
||||
/* End access and free the page. */
|
||||
if (channel->gref != GRANT_INVALID_REF)
|
||||
gnttab_end_foreign_access(channel->gref, page);
|
||||
else
|
||||
free_page(page);
|
||||
xenbus_teardown_ring(&page, 1, &channel->gref);
|
||||
|
||||
memset(channel, 0, sizeof(*channel));
|
||||
}
|
||||
|
@ -196,8 +193,7 @@ static int evtchnl_alloc(struct xen_snd_front_info *front_info, int index,
|
|||
enum xen_snd_front_evtchnl_type type)
|
||||
{
|
||||
struct xenbus_device *xb_dev = front_info->xb_dev;
|
||||
unsigned long page;
|
||||
grant_ref_t gref;
|
||||
void *page;
|
||||
irq_handler_t handler;
|
||||
char *handler_name = NULL;
|
||||
int ret;
|
||||
|
@ -207,12 +203,9 @@ static int evtchnl_alloc(struct xen_snd_front_info *front_info, int index,
|
|||
channel->index = index;
|
||||
channel->front_info = front_info;
|
||||
channel->state = EVTCHNL_STATE_DISCONNECTED;
|
||||
channel->gref = GRANT_INVALID_REF;
|
||||
page = get_zeroed_page(GFP_KERNEL);
|
||||
if (!page) {
|
||||
ret = -ENOMEM;
|
||||
ret = xenbus_setup_ring(xb_dev, GFP_KERNEL, &page, 1, &channel->gref);
|
||||
if (ret)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
handler_name = kasprintf(GFP_KERNEL, "%s-%s", XENSND_DRIVER_NAME,
|
||||
type == EVTCHNL_TYPE_REQ ?
|
||||
|
@ -226,33 +219,18 @@ static int evtchnl_alloc(struct xen_snd_front_info *front_info, int index,
|
|||
mutex_init(&channel->ring_io_lock);
|
||||
|
||||
if (type == EVTCHNL_TYPE_REQ) {
|
||||
struct xen_sndif_sring *sring = (struct xen_sndif_sring *)page;
|
||||
struct xen_sndif_sring *sring = page;
|
||||
|
||||
init_completion(&channel->u.req.completion);
|
||||
mutex_init(&channel->u.req.req_io_lock);
|
||||
SHARED_RING_INIT(sring);
|
||||
FRONT_RING_INIT(&channel->u.req.ring, sring, XEN_PAGE_SIZE);
|
||||
|
||||
ret = xenbus_grant_ring(xb_dev, sring, 1, &gref);
|
||||
if (ret < 0) {
|
||||
channel->u.req.ring.sring = NULL;
|
||||
goto fail;
|
||||
}
|
||||
XEN_FRONT_RING_INIT(&channel->u.req.ring, sring, XEN_PAGE_SIZE);
|
||||
|
||||
handler = evtchnl_interrupt_req;
|
||||
} else {
|
||||
ret = gnttab_grant_foreign_access(xb_dev->otherend_id,
|
||||
virt_to_gfn((void *)page), 0);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
channel->u.evt.page = (struct xensnd_event_page *)page;
|
||||
gref = ret;
|
||||
channel->u.evt.page = page;
|
||||
handler = evtchnl_interrupt_evt;
|
||||
}
|
||||
|
||||
channel->gref = gref;
|
||||
|
||||
ret = xenbus_alloc_evtchn(xb_dev, &channel->port);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
@ -279,8 +257,6 @@ static int evtchnl_alloc(struct xen_snd_front_info *front_info, int index,
|
|||
return 0;
|
||||
|
||||
fail:
|
||||
if (page)
|
||||
free_page(page);
|
||||
kfree(handler_name);
|
||||
dev_err(&xb_dev->dev, "Failed to allocate ring: %d\n", ret);
|
||||
return ret;
|
||||
|
|
|
@ -15,15 +15,6 @@
|
|||
|
||||
struct xen_snd_front_info;
|
||||
|
||||
#ifndef GRANT_INVALID_REF
|
||||
/*
|
||||
* FIXME: usage of grant reference 0 as invalid grant reference:
|
||||
* grant reference 0 is valid, but never exposed to a PV driver,
|
||||
* because of the fact it is already in use/reserved by the PV console.
|
||||
*/
|
||||
#define GRANT_INVALID_REF 0
|
||||
#endif
|
||||
|
||||
/* Timeout in ms to wait for backend to respond. */
|
||||
#define VSND_WAIT_BACK_MS 3000
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче