xen_backend: add grant table helpers

This patch adds grant table helper functions to the xen_backend code to
localize error reporting and use of xen_domid.

The patch also defers the call to xengnttab_open() until just before the
initialise method in XenDevOps is invoked. This method is responsible for
mapping the shared ring. No prior method requires access to the grant table.

Signed-off-by: Paul Durrant <paul.durrant@citrix.com>
Acked-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
This commit is contained in:
Paul Durrant 2018-05-17 16:35:51 +01:00 committed by Stefano Stabellini
parent 5c0d914a9b
commit 9838824aff
2 changed files with 144 additions and 12 deletions

View File

@ -106,6 +106,103 @@ int xen_be_set_state(struct XenDevice *xendev, enum xenbus_state state)
return 0;
}
void xen_be_set_max_grant_refs(struct XenDevice *xendev,
unsigned int nr_refs)
{
assert(xendev->ops->flags & DEVOPS_FLAG_NEED_GNTDEV);
if (xengnttab_set_max_grants(xendev->gnttabdev, nr_refs)) {
xen_pv_printf(xendev, 0, "xengnttab_set_max_grants failed: %s\n",
strerror(errno));
}
}
void *xen_be_map_grant_refs(struct XenDevice *xendev, uint32_t *refs,
unsigned int nr_refs, int prot)
{
void *ptr;
assert(xendev->ops->flags & DEVOPS_FLAG_NEED_GNTDEV);
ptr = xengnttab_map_domain_grant_refs(xendev->gnttabdev, nr_refs,
xen_domid, refs, prot);
if (!ptr) {
xen_pv_printf(xendev, 0,
"xengnttab_map_domain_grant_refs failed: %s\n",
strerror(errno));
}
return ptr;
}
void xen_be_unmap_grant_refs(struct XenDevice *xendev, void *ptr,
unsigned int nr_refs)
{
assert(xendev->ops->flags & DEVOPS_FLAG_NEED_GNTDEV);
if (xengnttab_unmap(xendev->gnttabdev, ptr, nr_refs)) {
xen_pv_printf(xendev, 0, "xengnttab_unmap failed: %s\n",
strerror(errno));
}
}
int xen_be_copy_grant_refs(struct XenDevice *xendev,
bool to_domain,
XenGrantCopySegment segs[],
unsigned int nr_segs)
{
xengnttab_grant_copy_segment_t *xengnttab_segs;
unsigned int i;
int rc;
assert(xendev->ops->flags & DEVOPS_FLAG_NEED_GNTDEV);
xengnttab_segs = g_new0(xengnttab_grant_copy_segment_t, nr_segs);
for (i = 0; i < nr_segs; i++) {
XenGrantCopySegment *seg = &segs[i];
xengnttab_grant_copy_segment_t *xengnttab_seg = &xengnttab_segs[i];
if (to_domain) {
xengnttab_seg->flags = GNTCOPY_dest_gref;
xengnttab_seg->dest.foreign.domid = xen_domid;
xengnttab_seg->dest.foreign.ref = seg->dest.foreign.ref;
xengnttab_seg->dest.foreign.offset = seg->dest.foreign.offset;
xengnttab_seg->source.virt = seg->source.virt;
} else {
xengnttab_seg->flags = GNTCOPY_source_gref;
xengnttab_seg->source.foreign.domid = xen_domid;
xengnttab_seg->source.foreign.ref = seg->source.foreign.ref;
xengnttab_seg->source.foreign.offset =
seg->source.foreign.offset;
xengnttab_seg->dest.virt = seg->dest.virt;
}
xengnttab_seg->len = seg->len;
}
rc = xengnttab_grant_copy(xendev->gnttabdev, nr_segs, xengnttab_segs);
if (rc) {
xen_pv_printf(xendev, 0, "xengnttab_copy failed: %s\n",
strerror(errno));
}
for (i = 0; i < nr_segs; i++) {
xengnttab_grant_copy_segment_t *xengnttab_seg =
&xengnttab_segs[i];
if (xengnttab_seg->status != GNTST_okay) {
xen_pv_printf(xendev, 0, "segment[%u] status: %d\n", i,
xengnttab_seg->status);
rc = -1;
}
}
g_free(xengnttab_segs);
return rc;
}
/*
* get xen backend device, allocate a new one if it doesn't exist.
*/
@ -149,18 +246,6 @@ static struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev,
}
qemu_set_cloexec(xenevtchn_fd(xendev->evtchndev));
if (ops->flags & DEVOPS_FLAG_NEED_GNTDEV) {
xendev->gnttabdev = xengnttab_open(NULL, 0);
if (xendev->gnttabdev == NULL) {
xen_pv_printf(NULL, 0, "can't open gnttab device\n");
xenevtchn_close(xendev->evtchndev);
qdev_unplug(DEVICE(xendev), NULL);
return NULL;
}
} else {
xendev->gnttabdev = NULL;
}
xen_pv_insert_xendev(xendev);
if (xendev->ops->alloc) {
@ -322,6 +407,16 @@ static int xen_be_try_initialise(struct XenDevice *xendev)
}
}
if (xendev->ops->flags & DEVOPS_FLAG_NEED_GNTDEV) {
xendev->gnttabdev = xengnttab_open(NULL, 0);
if (xendev->gnttabdev == NULL) {
xen_pv_printf(NULL, 0, "can't open gnttab device\n");
return -1;
}
} else {
xendev->gnttabdev = NULL;
}
if (xendev->ops->initialise) {
rc = xendev->ops->initialise(xendev);
}
@ -369,6 +464,10 @@ static void xen_be_disconnect(struct XenDevice *xendev, enum xenbus_state state)
xendev->ops->disconnect) {
xendev->ops->disconnect(xendev);
}
if (xendev->gnttabdev) {
xengnttab_close(xendev->gnttabdev);
xendev->gnttabdev = NULL;
}
if (xendev->be_state != state) {
xen_be_set_state(xendev, state);
}

View File

@ -42,6 +42,39 @@ void xen_be_register_common(void);
int xen_be_register(const char *type, struct XenDevOps *ops);
int xen_be_set_state(struct XenDevice *xendev, enum xenbus_state state);
int xen_be_bind_evtchn(struct XenDevice *xendev);
void xen_be_set_max_grant_refs(struct XenDevice *xendev,
unsigned int nr_refs);
void *xen_be_map_grant_refs(struct XenDevice *xendev, uint32_t *refs,
unsigned int nr_refs, int prot);
void xen_be_unmap_grant_refs(struct XenDevice *xendev, void *ptr,
unsigned int nr_refs);
typedef struct XenGrantCopySegment {
union {
void *virt;
struct {
uint32_t ref;
off_t offset;
} foreign;
} source, dest;
size_t len;
} XenGrantCopySegment;
int xen_be_copy_grant_refs(struct XenDevice *xendev,
bool to_domain, XenGrantCopySegment segs[],
unsigned int nr_segs);
static inline void *xen_be_map_grant_ref(struct XenDevice *xendev,
uint32_t ref, int prot)
{
return xen_be_map_grant_refs(xendev, &ref, 1, prot);
}
static inline void xen_be_unmap_grant_ref(struct XenDevice *xendev,
void *ptr)
{
return xen_be_unmap_grant_refs(xendev, ptr, 1);
}
/* actual backend drivers */
extern struct XenDevOps xen_console_ops; /* xen_console.c */