aboutsummaryrefslogtreecommitdiffstats
path: root/xen/common/trace.c
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2010-04-12 17:54:48 +0100
committerKeir Fraser <keir.fraser@citrix.com>2010-04-12 17:54:48 +0100
commitb690245b9f1569015522b67c37d846521f0250a8 (patch)
treee116fc7034f409ba3f7594b0cff4740199a7c047 /xen/common/trace.c
parent24488e9b291f63bbcd38583d4a3731bcf5a3612c (diff)
downloadxen-b690245b9f1569015522b67c37d846521f0250a8.tar.gz
xen-b690245b9f1569015522b67c37d846521f0250a8.tar.bz2
xen-b690245b9f1569015522b67c37d846521f0250a8.zip
xentrace: Bounds checking and error handling
Check tbuf_size to make sure that it will fit on the t_info struct allocated at boot. Also deal with allocation failures more gracefully. Signed-off-by: George Dunlap <george.dunlap@eu.citrix.com>
Diffstat (limited to 'xen/common/trace.c')
-rw-r--r--xen/common/trace.c65
1 files changed, 54 insertions, 11 deletions
diff --git a/xen/common/trace.c b/xen/common/trace.c
index 44cc8341d0..cd1f0fb7f6 100644
--- a/xen/common/trace.c
+++ b/xen/common/trace.c
@@ -48,6 +48,9 @@ integer_param("tbuf_size", opt_tbuf_size);
/* Pointers to the meta-data objects for all system trace buffers */
static struct t_info *t_info;
#define T_INFO_PAGES 2 /* Size fixed at 2 pages for now. */
+#define T_INFO_SIZE ((T_INFO_PAGES)*(PAGE_SIZE))
+/* t_info.tbuf_size + list of mfn offsets + 1 to round up / sizeof uint32_t */
+#define T_INFO_FIRST_OFFSET ((sizeof(int16_t) + NR_CPUS * sizeof(int16_t) + 1) / sizeof(uint32_t))
static DEFINE_PER_CPU_READ_MOSTLY(struct t_buf *, t_bufs);
static DEFINE_PER_CPU_READ_MOSTLY(unsigned char *, t_data);
static DEFINE_PER_CPU_READ_MOSTLY(spinlock_t, t_lock);
@@ -72,6 +75,15 @@ static cpumask_t tb_cpu_mask = CPU_MASK_ALL;
static u32 tb_event_mask = TRC_ALL;
/**
+ * check_tbuf_size - check to make sure that the proposed size will fit
+ * in the currently sized struct t_info.
+ */
+static inline int check_tbuf_size(int size)
+{
+ return (num_online_cpus() * size + T_INFO_FIRST_OFFSET) > (T_INFO_SIZE / sizeof(uint32_t));
+}
+
+/**
* alloc_trace_bufs - performs initialization of the per-cpu trace buffers.
*
* This function is called at start of day in order to initialize the per-cpu
@@ -87,7 +99,9 @@ static int alloc_trace_bufs(void)
unsigned long nr_pages;
/* Start after a fixed-size array of NR_CPUS */
uint32_t *t_info_mfn_list = (uint32_t *)t_info;
- int offset = (NR_CPUS * 2 + 1 + 1) / 4;
+ int offset = T_INFO_FIRST_OFFSET;
+
+ BUG_ON(check_tbuf_size(opt_tbuf_size));
if ( opt_tbuf_size == 0 )
return -EINVAL;
@@ -180,7 +194,8 @@ out_dealloc:
}
spin_unlock_irqrestore(&per_cpu(t_lock, cpu), flags);
}
- return -EINVAL;
+
+ return -ENOMEM;
}
@@ -197,19 +212,35 @@ static int tb_set_size(int size)
* boot time or via control tools, but not by both. Once buffers
* are created they cannot be destroyed.
*/
- if ( (opt_tbuf_size != 0) || (size <= 0) )
+ int ret = 0;
+
+
+
+ if ( (opt_tbuf_size != 0) )
{
- gdprintk(XENLOG_INFO, "tb_set_size from %d to %d not implemented\n",
- opt_tbuf_size, size);
+ if ( size != opt_tbuf_size )
+ gdprintk(XENLOG_INFO, "tb_set_size from %d to %d not implemented\n",
+ opt_tbuf_size, size);
return -EINVAL;
}
- opt_tbuf_size = size;
- if ( alloc_trace_bufs() != 0 )
+ if ( size <= 0 )
return -EINVAL;
- printk("Xen trace buffers: initialized\n");
- return 0;
+ if ( check_tbuf_size(size) )
+ {
+ gdprintk(XENLOG_INFO, "tb size %d too large\n", size);
+ return -EINVAL;
+ }
+
+ opt_tbuf_size = size;
+
+ if ( (ret = alloc_trace_bufs()) == 0 )
+ printk("Xen trace buffers: initialized\n");
+ else
+ opt_tbuf_size = 0;
+
+ return ret;
}
int trace_will_trace_event(u32 event)
@@ -265,13 +296,18 @@ void __init init_trace_bufs(void)
share_xen_page_with_privileged_guests(
virt_to_page(t_info) + i, XENSHARE_writable);
-
-
if ( opt_tbuf_size == 0 )
{
printk("Xen trace buffers: disabled\n");
return;
}
+ else if ( check_tbuf_size(opt_tbuf_size) )
+ {
+ gdprintk(XENLOG_INFO, "Xen trace buffers: "
+ "tb size %d too large, disabling\n",
+ opt_tbuf_size);
+ opt_tbuf_size = 0;
+ }
if ( alloc_trace_bufs() == 0 )
{
@@ -279,6 +315,13 @@ void __init init_trace_bufs(void)
wmb(); /* above must be visible before tb_init_done flag set */
tb_init_done = 1;
}
+ else
+ {
+ gdprintk(XENLOG_INFO, "Xen trace buffers: "
+ "allocation size %d failed, disabling\n",
+ opt_tbuf_size);
+ opt_tbuf_size = 0;
+ }
}
/**