common: add a new mappable resource type: XENMEM_resource_grant_table

This patch allows grant table frames to be mapped using the
XENMEM_acquire_resource memory op.

NOTE: This patch expands the on-stack mfn_list array in acquire_resource()
      but it is still small enough to remain on-stack.

NOTE: This patch also removes a bogus comment above the
      grant_to_status_frames() function.

Signed-off-by: Paul Durrant <paul.durrant@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
[Rebase over "Explicitly default to gnttab v1 during domain creation"]
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
This commit is contained in:
Paul Durrant authored and Andrew Cooper committed 2018-08-10 13:27:24 +01:00
1 parent 1237659523
commit 83fa6552ce
4 files changed
+165 -15

No files matched your search

+100 -14
View File
@@ -351,12 +351,17 @@ static inline void active_entry_release(struct active_grant_entry *act)
#define GRANT_STATUS_PER_PAGE (PAGE_SIZE / sizeof(grant_status_t)) #define GRANT_STATUS_PER_PAGE (PAGE_SIZE / sizeof(grant_status_t))
#define GRANT_PER_PAGE (PAGE_SIZE / sizeof(grant_entry_v2_t)) #define GRANT_PER_PAGE (PAGE_SIZE / sizeof(grant_entry_v2_t))
/* Number of grant table status entries. Caller must hold d's gr. table lock.*/
static inline unsigned int grant_to_status_frames(unsigned int grant_frames) static inline unsigned int grant_to_status_frames(unsigned int grant_frames)
{ {
return DIV_ROUND_UP(grant_frames * GRANT_PER_PAGE, GRANT_STATUS_PER_PAGE); return DIV_ROUND_UP(grant_frames * GRANT_PER_PAGE, GRANT_STATUS_PER_PAGE);
} }
static inline unsigned int status_to_grant_frames(unsigned int status_frames)
{
return DIV_ROUND_UP(status_frames * GRANT_STATUS_PER_PAGE, GRANT_PER_PAGE);
}
/* Check if the page has been paged out, or needs unsharing. /* Check if the page has been paged out, or needs unsharing.
If rc == GNTST_okay, *page contains the page struct with a ref taken. If rc == GNTST_okay, *page contains the page struct with a ref taken.
Caller must do put_page(*page). Caller must do put_page(*page).
@@ -3840,6 +3845,70 @@ int mem_sharing_gref_to_gfn(struct grant_table *gt, grant_ref_t ref,
} }
#endif #endif
/* caller must hold write lock */
static int gnttab_get_status_frame_mfn(struct domain *d,
unsigned long idx, mfn_t *mfn)
{
const struct grant_table *gt = d->grant_table;
ASSERT(gt->gt_version == 2);
if ( idx >= nr_status_frames(gt) )
{
unsigned long nr_status;
unsigned long nr_grant;
nr_status = idx + 1; /* sufficient frames to make idx valid */
if ( nr_status == 0 ) /* overflow? */
return -EINVAL;
nr_grant = status_to_grant_frames(nr_status);
if ( grant_to_status_frames(nr_grant) != nr_status ) /* overflow? */
return -EINVAL;
if ( nr_grant <= gt->max_grant_frames )
gnttab_grow_table(d, nr_grant);
/* check whether gnttab_grow_table() succeeded */
if ( idx >= nr_status_frames(gt) )
return -EINVAL;
}
*mfn = _mfn(virt_to_mfn(gt->status[idx]));
return 0;
}
/* caller must hold write lock */
static int gnttab_get_shared_frame_mfn(struct domain *d,
unsigned long idx, mfn_t *mfn)
{
const struct grant_table *gt = d->grant_table;
ASSERT(gt->gt_version != 0);
if ( idx >= nr_grant_frames(gt) )
{
unsigned long nr_grant;
nr_grant = idx + 1; /* sufficient frames to make idx valid */
if ( nr_grant == 0 ) /* overflow? */
return -EINVAL;
if ( nr_grant <= gt->max_grant_frames )
gnttab_grow_table(d, nr_grant);
/* check whether gnttab_grow_table() succeeded */
if ( idx >= nr_grant_frames(gt) )
return -EINVAL;
}
*mfn = _mfn(virt_to_mfn(gt->shared_raw[idx]));
return 0;
}
int gnttab_map_frame(struct domain *d, unsigned long idx, gfn_t gfn, int gnttab_map_frame(struct domain *d, unsigned long idx, gfn_t gfn,
mfn_t *mfn) mfn_t *mfn)
{ {
@@ -3854,21 +3923,11 @@ int gnttab_map_frame(struct domain *d, unsigned long idx, gfn_t gfn,
{ {
idx &= ~XENMAPIDX_grant_table_status; idx &= ~XENMAPIDX_grant_table_status;
status = true; status = true;
if ( idx < nr_status_frames(gt) )
*mfn = _mfn(virt_to_mfn(gt->status[idx])); rc = gnttab_get_status_frame_mfn(d, idx, mfn);
else
rc = -EINVAL;
} }
else else
{ rc = gnttab_get_shared_frame_mfn(d, idx, mfn);
if ( (idx >= nr_grant_frames(gt)) && (idx < gt->max_grant_frames) )
gnttab_grow_table(d, idx + 1);
if ( idx < nr_grant_frames(gt) )
*mfn = _mfn(virt_to_mfn(gt->shared_raw[idx]));
else
rc = -EINVAL;
}
if ( !rc && paging_mode_translate(d) && if ( !rc && paging_mode_translate(d) &&
!gfn_eq(gnttab_get_frame_gfn(gt, status, idx), INVALID_GFN) ) !gfn_eq(gnttab_get_frame_gfn(gt, status, idx), INVALID_GFN) )
@@ -3883,6 +3942,33 @@ int gnttab_map_frame(struct domain *d, unsigned long idx, gfn_t gfn,
return rc; return rc;
} }
int gnttab_get_shared_frame(struct domain *d, unsigned long idx,
mfn_t *mfn)
{
struct grant_table *gt = d->grant_table;
int rc;
grant_write_lock(gt);
rc = gnttab_get_shared_frame_mfn(d, idx, mfn);
grant_write_unlock(gt);
return rc;
}
int gnttab_get_status_frame(struct domain *d, unsigned long idx,
mfn_t *mfn)
{
struct grant_table *gt = d->grant_table;
int rc;
grant_write_lock(gt);
rc = (gt->gt_version == 2) ?
gnttab_get_status_frame_mfn(d, idx, mfn) : -EINVAL;
grant_write_unlock(gt);
return rc;
}
static void gnttab_usage_print(struct domain *rd) static void gnttab_usage_print(struct domain *rd)
{ {
int first = 1; int first = 1;
+55 -1
View File
@@ -23,6 +23,7 @@
#include <xen/numa.h> #include <xen/numa.h>
#include <xen/mem_access.h> #include <xen/mem_access.h>
#include <xen/trace.h> #include <xen/trace.h>
#include <xen/grant_table.h>
#include <asm/current.h> #include <asm/current.h>
#include <asm/hardirq.h> #include <asm/hardirq.h>
#include <asm/p2m.h> #include <asm/p2m.h>
@@ -982,6 +983,44 @@ static long xatp_permission_check(struct domain *d, unsigned int space)
return xsm_add_to_physmap(XSM_TARGET, current->domain, d); return xsm_add_to_physmap(XSM_TARGET, current->domain, d);
} }
static int acquire_grant_table(struct domain *d, unsigned int id,
unsigned long frame,
unsigned int nr_frames,
xen_pfn_t mfn_list[])
{
unsigned int i = nr_frames;
/* Iterate backwards in case table needs to grow */
while ( i-- != 0 )
{
mfn_t mfn = INVALID_MFN;
int rc;
switch ( id )
{
case XENMEM_resource_grant_table_id_shared:
rc = gnttab_get_shared_frame(d, frame + i, &mfn);
break;
case XENMEM_resource_grant_table_id_status:
rc = gnttab_get_status_frame(d, frame + i, &mfn);
break;
default:
rc = -EINVAL;
break;
}
if ( rc )
return rc;
ASSERT(!mfn_eq(mfn, INVALID_MFN));
mfn_list[i] = mfn_x(mfn);
}
return 0;
}
static int acquire_resource( static int acquire_resource(
XEN_GUEST_HANDLE_PARAM(xen_mem_acquire_resource_t) arg) XEN_GUEST_HANDLE_PARAM(xen_mem_acquire_resource_t) arg)
{ {
@@ -992,7 +1031,7 @@ static int acquire_resource(
* moment since they are small, but if they need to grow in future * moment since they are small, but if they need to grow in future
* use-cases then per-CPU arrays or heap allocations may be required. * use-cases then per-CPU arrays or heap allocations may be required.
*/ */
xen_pfn_t mfn_list[2]; xen_pfn_t mfn_list[32];
int rc; int rc;
if ( copy_from_guest(&xmar, arg, 1) ) if ( copy_from_guest(&xmar, arg, 1) )
@@ -1027,6 +1066,11 @@ static int acquire_resource(
switch ( xmar.type ) switch ( xmar.type )
{ {
case XENMEM_resource_grant_table:
rc = acquire_grant_table(d, xmar.id, xmar.frame, xmar.nr_frames,
mfn_list);
break;
default: default:
rc = arch_acquire_resource(d, xmar.type, xmar.id, xmar.frame, rc = arch_acquire_resource(d, xmar.type, xmar.id, xmar.frame,
xmar.nr_frames, mfn_list, &xmar.flags); xmar.nr_frames, mfn_list, &xmar.flags);
@@ -1046,6 +1090,16 @@ static int acquire_resource(
xen_pfn_t gfn_list[ARRAY_SIZE(mfn_list)]; xen_pfn_t gfn_list[ARRAY_SIZE(mfn_list)];
unsigned int i; unsigned int i;
/*
* FIXME: Until foreign pages inserted into the P2M are properly
* reference counted, it is unsafe to allow mapping of
* non-caller-owned resource pages unless the caller is
* the hardware domain.
*/
if ( !(xmar.flags & XENMEM_rsrc_acq_caller_owned) &&
!is_hardware_domain(currd) )
return -EACCES;
if ( copy_from_guest(gfn_list, xmar.frame_list, xmar.nr_frames) ) if ( copy_from_guest(gfn_list, xmar.frame_list, xmar.nr_frames) )
rc = -EFAULT; rc = -EFAULT;
+6
View File
@@ -611,14 +611,20 @@ struct xen_mem_acquire_resource {
uint16_t type; uint16_t type;
#define XENMEM_resource_ioreq_server 0 #define XENMEM_resource_ioreq_server 0
#define XENMEM_resource_grant_table 1
/* /*
* IN - a type-specific resource identifier, which must be zero * IN - a type-specific resource identifier, which must be zero
* unless stated otherwise. * unless stated otherwise.
* *
* type == XENMEM_resource_ioreq_server -> id == ioreq server id * type == XENMEM_resource_ioreq_server -> id == ioreq server id
* type == XENMEM_resource_grant_table -> id defined below
*/ */
uint32_t id; uint32_t id;
#define XENMEM_resource_grant_table_id_shared 0
#define XENMEM_resource_grant_table_id_status 1
/* /*
* IN/OUT - As an IN parameter number of frames of the resource * IN/OUT - As an IN parameter number of frames of the resource
* to be mapped. However, if the specified value is 0 and * to be mapped. However, if the specified value is 0 and
+4
View File
@@ -58,6 +58,10 @@ int mem_sharing_gref_to_gfn(struct grant_table *gt, grant_ref_t ref,
int gnttab_map_frame(struct domain *d, unsigned long idx, gfn_t gfn, int gnttab_map_frame(struct domain *d, unsigned long idx, gfn_t gfn,
mfn_t *mfn); mfn_t *mfn);
int gnttab_get_shared_frame(struct domain *d, unsigned long idx,
mfn_t *mfn);
int gnttab_get_status_frame(struct domain *d, unsigned long idx,
mfn_t *mfn);
unsigned int gnttab_dom0_frames(void); unsigned int gnttab_dom0_frames(void);
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.