---
V11:
- add comment in include/asm-arm/grant_table.h (Julien Grall)
V10:
- lower INITIAL_NR_GRANT_FRAMES value to 1
- removed no longer needed variables (Jan Beulich)
- stream lined messages (Jan Beulich)
- corrected setting of gnttab_size on ARM
V9:
- add caps for per-domain limits (Jan Beulich)
- some error messages enhanced (Jan Beulich)
- adjusted some types (Jan Beulich)
- merge parts of (former) patch 14 into this one
- make parameters changeable at runtime
- limit size of dom0's grant table on ARM
- set default max_grant_frames to 64
V6:
- several changes due to new patch order
V3:
- correct error message (Paul Durrant)
---
docs/misc/xen-command-line.markdown | 25 +++---
xen/arch/arm/domain_build.c | 6 +-
xen/common/compat/grant_table.c | 31 ++-----
xen/common/grant_table.c | 156 +++++++++++++++++++++---------------
xen/include/asm-arm/grant_table.h | 20 ++++-
xen/include/asm-x86/grant_table.h | 7 +-
xen/include/xen/grant_table.h | 5 +-
7 files changed, 138 insertions(+), 112 deletions(-)
diff --git a/docs/misc/xen-command-line.markdown
b/docs/misc/xen-command-line.markdown
index 9797c8db2d..9b6cd8e9d0 100644
--- a/docs/misc/xen-command-line.markdown
+++ b/docs/misc/xen-command-line.markdown
@@ -875,27 +875,28 @@ Specify which console gdbstub should use. See **console**.
### gnttab\_max\_frames
> `= <integer>`
-> Default: `32`
+> Default: `64`
+
+> Can be modified at runtime
Specify the maximum number of frames which any domain may use as part
-of its grant table.
+of its grant table. This value is an upper boundary of the per-domain
+value settable via Xen tools.
+
+Dom0 is using this value for sizing its grant table.
### gnttab\_max\_maptrack\_frames
> `= <integer>`
-> Default: `8 * gnttab_max_frames`
-
-Specify the maximum number of frames to use as part of a domains
-maptrack array.
+> Default: `1024`
-### gnttab\_max\_nr\_frames
-> `= <integer>`
+> Can be modified at runtime
-*Deprecated*
-Use **gnttab\_max\_frames** and **gnttab\_max\_maptrack\_frames** instead.
+Specify the maximum number of frames to use as part of a domains
+maptrack array. This value is an upper boundary of the per-domain
+value settable via Xen tools.
-Specify the maximum number of frames per grant table operation and the
-maximum number of maptrack frames domain.
+Dom0 is using this value for sizing its maptrack table.
### guest\_loglvl
> `= <level>[/<rate-limited level>]` where level is `none | error | warning |
info | debug | all`
diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index c34238ec1b..3723dc3f78 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -2095,11 +2095,7 @@ static void __init find_gnttab_region(struct domain *d,
* enough space for a large grant table
*/
kinfo->gnttab_start = __pa(_stext);
- kinfo->gnttab_size = (_etext - _stext) & PAGE_MASK;
-
- /* Make sure the grant table will fit in the region */
- if ( (kinfo->gnttab_size >> PAGE_SHIFT) < max_grant_frames )
- panic("Cannot find a space for the grant table region\n");
+ kinfo->gnttab_size = gnttab_dom0_frames() << PAGE_SHIFT;
#ifdef CONFIG_ARM_32
/*
diff --git a/xen/common/compat/grant_table.c b/xen/common/compat/grant_table.c
index cce3ff0b9a..ff1d678f01 100644
--- a/xen/common/compat/grant_table.c
+++ b/xen/common/compat/grant_table.c
@@ -157,21 +157,14 @@ int compat_grant_table_op(unsigned int cmd,
unsigned int max_frame_list_size_in_page =
(COMPAT_ARG_XLAT_SIZE - sizeof(*nat.setup)) /
sizeof(*nat.setup->frame_list.p);
- if ( max_frame_list_size_in_page < max_grant_frames )
- {
- gdprintk(XENLOG_WARNING,
- "max_grant_frames is too large (%u,%u)\n",
- max_grant_frames, max_frame_list_size_in_page);
- rc = -EINVAL;
- }
- else
- {
+
#define XLAT_gnttab_setup_table_HNDL_frame_list(_d_, _s_) \
- set_xen_guest_handle((_d_)->frame_list, (unsigned long
*)(nat.setup + 1))
- XLAT_gnttab_setup_table(nat.setup, &cmp.setup);
+ set_xen_guest_handle((_d_)->frame_list, (unsigned long
*)(nat.setup + 1))
+ XLAT_gnttab_setup_table(nat.setup, &cmp.setup);
#undef XLAT_gnttab_setup_table_HNDL_frame_list
- rc = gnttab_setup_table(guest_handle_cast(nat.uop,
gnttab_setup_table_t), 1);
- }
+ rc = gnttab_setup_table(guest_handle_cast(nat.uop,
+
gnttab_setup_table_t),
+ 1, max_frame_list_size_in_page);
}
ASSERT(rc <= 0);
if ( rc == 0 )
@@ -294,16 +287,6 @@ int compat_grant_table_op(unsigned int cmd,
rc = -EFAULT;
break;
}
- if ( max_frame_list_size_in_pages <
- grant_to_status_frames(max_grant_frames) )
- {
- gdprintk(XENLOG_WARNING,
- "grant_to_status_frames(max_grant_frames) is too large
(%u,%u)\n",
- grant_to_status_frames(max_grant_frames),
- max_frame_list_size_in_pages);
- rc = -EINVAL;
- break;
- }
#define XLAT_gnttab_get_status_frames_HNDL_frame_list(_d_, _s_) \
set_xen_guest_handle((_d_)->frame_list, (uint64_t
*)(nat.get_status + 1))
@@ -312,7 +295,7 @@ int compat_grant_table_op(unsigned int cmd,
rc = gnttab_get_status_frames(
guest_handle_cast(nat.uop, gnttab_get_status_frames_t),
- count);
+ count, max_frame_list_size_in_pages);
if ( rc >= 0 )
{
#define XLAT_gnttab_get_status_frames_HNDL_frame_list(_d_, _s_) \
diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c
index 71706f5cba..7c328b0a62 100644
--- a/xen/common/grant_table.c
+++ b/xen/common/grant_table.c
@@ -54,6 +54,9 @@ struct grant_table {
* what version to use yet.
*/
unsigned int gt_version;
+ /* Resource limits of the domain. */
+ unsigned int max_grant_frames;
+ unsigned int max_maptrack_frames;
/* Table size. Number of frames shared with guest */
unsigned int nr_grant_frames;
/* Number of grant status frames shared with guest (for version 2) */
@@ -78,23 +81,18 @@ struct grant_table {
#ifndef DEFAULT_MAX_NR_GRANT_FRAMES /* to allow arch to override */
/* Default maximum size of a grant table. [POLICY] */
-#define DEFAULT_MAX_NR_GRANT_FRAMES 32
+#define DEFAULT_MAX_NR_GRANT_FRAMES 64
#endif
-unsigned int __read_mostly max_grant_frames;
-integer_param("gnttab_max_frames", max_grant_frames);
+static unsigned int __read_mostly max_grant_frames =
+ DEFAULT_MAX_NR_GRANT_FRAMES;
+integer_runtime_param("gnttab_max_frames", max_grant_frames);
-/* The maximum number of grant mappings is defined as a multiplier of the
- * maximum number of grant table entries. This defines the multiplier used.
- * Pretty arbitrary. [POLICY]
- * As gnttab_max_nr_frames has been deprecated, this multiplier is deprecated
too.
- * New options allow to set max_maptrack_frames and
- * map_grant_table_frames independently.
- */
#define DEFAULT_MAX_MAPTRACK_FRAMES 1024
-static unsigned int __read_mostly max_maptrack_frames;
-integer_param("gnttab_max_maptrack_frames", max_maptrack_frames);
+static unsigned int __read_mostly max_maptrack_frames =
+ DEFAULT_MAX_MAPTRACK_FRAMES;
+integer_runtime_param("gnttab_max_maptrack_frames", max_maptrack_frames);
/*
* Note that the three values below are effectively part of the ABI, even if
@@ -290,8 +288,8 @@ num_act_frames_from_sha_frames(const unsigned int num)
return DIV_ROUND_UP(num * sha_per_page, ACGNT_PER_PAGE);
}
-#define max_nr_active_grant_frames \
- num_act_frames_from_sha_frames(max_grant_frames)
+#define max_nr_active_grant_frames(gt) \
+ num_act_frames_from_sha_frames((gt)->max_grant_frames)
static inline unsigned int
nr_active_grant_frames(struct grant_table *gt)
@@ -530,7 +528,7 @@ get_maptrack_handle(
* out of memory, try stealing an entry from another VCPU (in case the
* guest isn't mapping across its VCPUs evenly).
*/
- if ( nr_maptrack_frames(lgt) < max_maptrack_frames )
+ if ( nr_maptrack_frames(lgt) < lgt->max_maptrack_frames )
new_mt = alloc_xenheap_page();
if ( !new_mt )
@@ -1673,7 +1671,7 @@ gnttab_grow_table(struct domain *d, unsigned int
req_nr_frames)
if ( req_nr_frames < INITIAL_NR_GRANT_FRAMES )
req_nr_frames = INITIAL_NR_GRANT_FRAMES;
- ASSERT(req_nr_frames <= max_grant_frames);
+ ASSERT(req_nr_frames <= gt->max_grant_frames);
gdprintk(XENLOG_INFO,
"Expanding dom (%d) grant table from (%d) to (%d) frames.\n",
@@ -1730,7 +1728,8 @@ active_alloc_failed:
}
static int
-grant_table_init(struct domain *d, struct grant_table *gt)
+grant_table_init(struct domain *d, struct grant_table *gt,
+ unsigned int grant_frames, unsigned int maptrack_frames)
{
int ret;
@@ -1742,25 +1741,31 @@ grant_table_init(struct domain *d, struct grant_table *gt)
goto unlock;
}
+ gt->max_grant_frames = grant_frames;
+ gt->max_maptrack_frames = maptrack_frames;
+
/* Active grant table. */
gt->active = xzalloc_array(struct active_grant_entry *,
- max_nr_active_grant_frames);
+ max_nr_active_grant_frames(gt));
if ( gt->active == NULL )
goto no_mem;
/* Tracking of mapped foreign frames table */
- gt->maptrack = vzalloc(max_maptrack_frames * sizeof(*gt->maptrack));
- if ( gt->maptrack == NULL )
- goto no_mem;
+ if ( gt->max_maptrack_frames )
+ {
+ gt->maptrack = vzalloc(gt->max_maptrack_frames *
sizeof(*gt->maptrack));
+ if ( gt->maptrack == NULL )
+ goto no_mem;
+ }
/* Shared grant table. */
- gt->shared_raw = xzalloc_array(void *, max_grant_frames);
+ gt->shared_raw = xzalloc_array(void *, gt->max_grant_frames);
if ( gt->shared_raw == NULL )
goto no_mem;
/* Status pages for grant table - for version 2 */
gt->status = xzalloc_array(grant_status_t *,
- grant_to_status_frames(max_grant_frames));
+ grant_to_status_frames(gt->max_grant_frames));
if ( gt->status == NULL )
goto no_mem;
@@ -1793,7 +1798,8 @@ grant_table_init(struct domain *d, struct grant_table *gt)
static long
gnttab_setup_table(
- XEN_GUEST_HANDLE_PARAM(gnttab_setup_table_t) uop, unsigned int count)
+ XEN_GUEST_HANDLE_PARAM(gnttab_setup_table_t) uop, unsigned int count,
+ unsigned int limit_max)
{
struct vcpu *curr = current;
struct gnttab_setup_table op;
@@ -1807,15 +1813,6 @@ gnttab_setup_table(
if ( unlikely(copy_from_guest(&op, uop, 1)) )
return -EFAULT;
- if ( unlikely(op.nr_frames > max_grant_frames) )
- {
- gdprintk(XENLOG_INFO, "Xen only supports up to %d grant-table frames"
- " per domain.\n",
- max_grant_frames);
- op.status = GNTST_general_error;
- goto out;
- }
-
if ( !guest_handle_okay(op.frame_list, op.nr_frames) )
return -EFAULT;
@@ -1835,6 +1832,21 @@ gnttab_setup_table(
gt = d->grant_table;
grant_write_lock(gt);
+ if ( unlikely(op.nr_frames > gt->max_grant_frames) )
+ {
+ gdprintk(XENLOG_INFO, "d%d is limited to %u grant-table frames.\n",
+ d->domain_id, gt->max_grant_frames);
+ op.status = GNTST_general_error;
+ goto unlock;
+ }
+ if ( unlikely(limit_max < op.nr_frames) )
+ {
+ gdprintk(XENLOG_WARNING, "nr_frames for d%d is too large (%u,%u)\n",
+ d->domain_id, op.nr_frames, limit_max);
+ op.status = GNTST_general_error;
+ goto unlock;
+ }
+
if ( gt->gt_version == 0 )
gt->gt_version = 1;
@@ -1844,8 +1856,9 @@ gnttab_setup_table(
!gnttab_grow_table(d, op.nr_frames) )
{
gdprintk(XENLOG_INFO,
- "Expand grant table to %u failed. Current: %u Max: %u\n",
- op.nr_frames, nr_grant_frames(gt), max_grant_frames);
+ "Expand grant table of d%d to %u failed. Current: %u Max:
%u\n",
+ d->domain_id, op.nr_frames, nr_grant_frames(gt),
+ gt->max_grant_frames);
op.status = GNTST_general_error;
goto unlock;
}
@@ -1880,6 +1893,7 @@ gnttab_query_size(
{
struct gnttab_query_size op;
struct domain *d;
+ struct grant_table *gt;
if ( count != 1 )
return -EINVAL;
@@ -1900,13 +1914,15 @@ gnttab_query_size(
goto out;
}
- grant_read_lock(d->grant_table);
+ gt = d->grant_table;
+
+ grant_read_lock(gt);
- op.nr_frames = nr_grant_frames(d->grant_table);
- op.max_nr_frames = max_grant_frames;
+ op.nr_frames = nr_grant_frames(gt);
+ op.max_nr_frames = gt->max_grant_frames;
op.status = GNTST_okay;
- grant_read_unlock(d->grant_table);
+ grant_read_unlock(gt);
out:
if ( d )
@@ -2981,7 +2997,7 @@
gnttab_set_version(XEN_GUEST_HANDLE_PARAM(gnttab_set_version_t) uop)
static long
gnttab_get_status_frames(XEN_GUEST_HANDLE_PARAM(gnttab_get_status_frames_t)
uop,
- int count)
+ unsigned int count, unsigned int limit_max)
{
gnttab_get_status_frames_t op;
struct domain *d;
@@ -3021,9 +3037,19 @@
gnttab_get_status_frames(XEN_GUEST_HANDLE_PARAM(gnttab_get_status_frames_t) uop,
if ( unlikely(op.nr_frames > nr_status_frames(gt)) )
{
- gdprintk(XENLOG_INFO, "Guest requested addresses for %d grant status "
- "frames, but only %d are available.\n",
- op.nr_frames, nr_status_frames(gt));
+ gdprintk(XENLOG_INFO, "Requested addresses of d%d for %u grant "
+ "status frames, but has only %u.\n",
+ d->domain_id, op.nr_frames, nr_status_frames(gt));
+ op.status = GNTST_general_error;
+ goto unlock;
+ }
+
+ if ( unlikely(limit_max < grant_to_status_frames(op.nr_frames)) )
+ {
+ gdprintk(XENLOG_WARNING,
+ "grant_to_status_frames(%u) for d%d is too large (%u,%u)\n",
+ op.nr_frames, d->domain_id,
+ grant_to_status_frames(op.nr_frames), limit_max);
op.status = GNTST_general_error;
goto unlock;
}
@@ -3336,7 +3362,7 @@ do_grant_table_op(
case GNTTABOP_setup_table:
rc = gnttab_setup_table(
- guest_handle_cast(uop, gnttab_setup_table_t), count);
+ guest_handle_cast(uop, gnttab_setup_table_t), count, UINT_MAX);
ASSERT(rc <= 0);
break;
@@ -3385,7 +3411,8 @@ do_grant_table_op(
case GNTTABOP_get_status_frames:
rc = gnttab_get_status_frames(
- guest_handle_cast(uop, gnttab_get_status_frames_t), count);
+ guest_handle_cast(uop, gnttab_get_status_frames_t), count,
+ UINT_MAX);
break;
case GNTTABOP_get_version:
@@ -3465,7 +3492,7 @@ grant_table_create(
if ( d->domain_id == 0 )
{
- ret = grant_table_init(d, t);
+ ret = grant_table_init(d, t, gnttab_dom0_frames(),
max_maptrack_frames);
}
return ret;
@@ -3666,11 +3693,15 @@ int grant_table_set_limits(struct domain *d, unsigned
int grant_frames,
{
struct grant_table *gt = d->grant_table;
+ if ( grant_frames < INITIAL_NR_GRANT_FRAMES ||
+ grant_frames > max_grant_frames ||
+ maptrack_frames > max_maptrack_frames )
+ return -EINVAL;
if ( !gt )
return -ENOENT;
/* Set limits. */
- return grant_table_init(d, gt);
+ return grant_table_init(d, gt, grant_frames, maptrack_frames);
}
#ifdef CONFIG_HAS_MEM_SHARING
@@ -3742,7 +3773,7 @@ int gnttab_map_frame(struct domain *d, unsigned long idx,
gfn_t gfn,
}
else
{
- if ( (idx >= nr_grant_frames(gt)) && (idx < max_grant_frames) )
+ if ( (idx >= nr_grant_frames(gt)) && (idx < gt->max_grant_frames) )
gnttab_grow_table(d, idx + 1);
if ( idx < nr_grant_frames(gt) )
@@ -3770,6 +3801,12 @@ static void gnttab_usage_print(struct domain *rd)
grant_read_lock(gt);
+ printk("grant-table for remote d%d (v%u)\n"
+ " %u frames (%u max), %u maptrack frames (%u max)\n",
+ rd->domain_id, gt->gt_version,
+ nr_grant_frames(gt), gt->max_grant_frames,
+ nr_maptrack_frames(gt), gt->max_maptrack_frames);
+
for ( ref = 0; ref != nr_grant_entries(gt); ref++ )
{
struct active_grant_entry *act;
@@ -3797,12 +3834,7 @@ static void gnttab_usage_print(struct domain *rd)
status = status_entry(gt, ref);
}
- if ( first )
- {
- printk("grant-table for remote domain:%5d (v%d)\n",
- rd->domain_id, gt->gt_version);
- first = 0;
- }
+ first = 0;
/* [0xXXX] ddddd 0xXXXXXX 0xXXXXXXXX ddddd 0xXXXXXX 0xXX */
printk("[0x%03x] %5d 0x%06lx 0x%08x %5d 0x%06"PRIx64" 0x%02x\n",
@@ -3814,8 +3846,7 @@ static void gnttab_usage_print(struct domain *rd)
grant_read_unlock(gt);
if ( first )
- printk("grant-table for remote domain:%5d ... "
- "no active grant table entries\n", rd->domain_id);
+ printk("no active grant table entries\n");
}
static void gnttab_usage_print_all(unsigned char key)
@@ -3829,20 +3860,17 @@ static void gnttab_usage_print_all(unsigned char key)
static int __init gnttab_usage_init(void)
{
- BUILD_BUG_ON(DEFAULT_MAX_MAPTRACK_FRAMES < DEFAULT_MAX_NR_GRANT_FRAMES);
-
- if ( !max_grant_frames )
- max_grant_frames = DEFAULT_MAX_NR_GRANT_FRAMES;
-
- if ( !max_maptrack_frames )
- max_maptrack_frames = DEFAULT_MAX_MAPTRACK_FRAMES;
-
register_keyhandler('g', gnttab_usage_print_all,
"print grant table usage", 1);
return 0;
}
__initcall(gnttab_usage_init);
+unsigned int __init gnttab_dom0_frames(void)
+{
+ return min(max_grant_frames, gnttab_dom0_max());
+}
+
/*
* Local variables:
* mode: C
diff --git a/xen/include/asm-arm/grant_table.h
b/xen/include/asm-arm/grant_table.h
index 30db2d1616..0dfdc5577f 100644
--- a/xen/include/asm-arm/grant_table.h
+++ b/xen/include/asm-arm/grant_table.h
@@ -2,9 +2,11 @@
#define __ASM_GRANT_TABLE_H__
#include <xen/grant_table.h>
+#include <xen/kernel.h>
+#include <xen/pfn.h>
#include <xen/sched.h>
-#define INITIAL_NR_GRANT_FRAMES 4
+#define INITIAL_NR_GRANT_FRAMES 1U
struct grant_table_arch {
gfn_t *gfn;
@@ -26,9 +28,21 @@ static inline int replace_grant_supported(void)
return 1;
}
+/*
+ * The region used by Xen on the memory will never be mapped in DOM0
+ * memory layout. Therefore it can be used for the grant table.
+ *
+ * Only use the text section as it's always present and will contain
+ * enough space for a large grant table
+ */
+static inline unsigned int gnttab_dom0_max(void)
+{
+ return PFN_DOWN(_etext - _stext);
+}
+
#define gnttab_init_arch(gt) \
({ \
- (gt)->arch.gfn = xzalloc_array(gfn_t, max_grant_frames); \
+ (gt)->arch.gfn = xzalloc_array(gfn_t, (gt)->max_grant_frames); \
( (gt)->arch.gfn ? 0 : -ENOMEM ); \
})
@@ -52,7 +66,7 @@ static inline int replace_grant_supported(void)
#define gnttab_shared_gmfn(d, t, i) \
( ((i >= nr_grant_frames(t)) && \
- (i < max_grant_frames)) ? 0 : gfn_x(t->arch.gfn[i]))
+ (i < (t)->max_grant_frames))? 0 : gfn_x((t)->arch.gfn[i]))
#define gnttab_need_iommu_mapping(d) \
(is_domain_direct_mapped(d) && need_iommu(d))
diff --git a/xen/include/asm-x86/grant_table.h
b/xen/include/asm-x86/grant_table.h
index 1b93c5720d..d9157e4417 100644
--- a/xen/include/asm-x86/grant_table.h
+++ b/xen/include/asm-x86/grant_table.h
@@ -12,7 +12,7 @@
#include <asm/hvm/grant_table.h>
#include <asm/pv/grant_table.h>
-#define INITIAL_NR_GRANT_FRAMES 4
+#define INITIAL_NR_GRANT_FRAMES 1U
struct grant_table_arch {
};
@@ -39,6 +39,11 @@ static inline int replace_grant_host_mapping(uint64_t addr,
unsigned long frame,
return replace_grant_pv_mapping(addr, frame, new_addr, flags);
}
+static inline unsigned int gnttab_dom0_max(void)
+{
+ return UINT_MAX;
+}
+
#define gnttab_init_arch(gt) 0
#define gnttab_destroy_arch(gt) do {} while ( 0 )
#define gnttab_set_frame_gfn(gt, idx, gfn) do {} while ( 0 )
diff --git a/xen/include/xen/grant_table.h b/xen/include/xen/grant_table.h
index d2bd2416c4..b3a95fda58 100644
--- a/xen/include/xen/grant_table.h
+++ b/xen/include/xen/grant_table.h
@@ -31,9 +31,6 @@
struct grant_table;
-/* The maximum size of a grant table. */
-extern unsigned int max_grant_frames;
-
/* Create/destroy per-domain grant table context. */
int grant_table_create(
struct domain *d);
@@ -59,4 +56,6 @@ 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,
mfn_t *mfn);
+unsigned int gnttab_dom0_frames(void);
+
#endif /* __XEN_GRANT_TABLE_H__ */