These patches address issues in the kernel part of xenoprof: * Ill-advised use of on_each_cpu() can lead to sleep with interrupts disabled. * Race conditions in active_domains code. * Cleanup of active_domains code. Comments welcome. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Markus Armbruster
2006-May-15 16:31 UTC
[Xen-devel] [PATCH 1/3] xenoprof fixes: sleep with interrupts disabled
Ill-advised use of on_each_cpu() can lead to sleep with interrupts
disabled. This is best explained with a backtrace:
BUG: sleeping function called from invalid context at
/home/armbru/linux-2.6.tip-xen-quintela.hg/mm/slab.c:2783
in_atomic():0, irqs_disabled():1
[<c0104f36>] show_trace+0x13/0x15
[<c0105439>] dump_stack+0x18/0x1c
[<c01161ac>] __might_sleep+0x9f/0xa7
[<c0158823>] __kmalloc+0x65/0x110
[<c018e01d>] proc_create+0x8d/0xe2
[<c018e12d>] proc_mkdir_mode+0x1a/0x4d
[<c018e173>] proc_mkdir+0x13/0x15
[<c013de9b>] register_handler_proc+0x90/0x9e
[<c013d729>] setup_irq+0xdf/0xf5
[<c013d7a9>] request_irq+0x6a/0x8a
[<c0231817>] bind_virq_to_irqhandler+0xe3/0x101
[<f4c83b02>] bind_virq_cpu+0x28/0x62 [oprofile]
[<c0121453>] on_each_cpu+0x36/0x5d
[<f4c83c3b>] xenoprof_setup+0x22/0x14a [oprofile]
[<f4c820bf>] oprofile_setup+0x45/0x8b [oprofile]
[<f4c82fa3>] event_buffer_open+0x3e/0x62 [oprofile]
[<c0159eda>] __dentry_open+0xc7/0x1b0
[<c015a034>] nameidata_to_filp+0x20/0x34
[<c015a078>] do_filp_open+0x30/0x39
[<c015afe6>] do_sys_open+0x40/0xb0
[<c015b07f>] sys_open+0x13/0x15
[<c01048cf>] syscall_call+0x7/0xb
on_each_cpu() disables interrupts. proc_create() calls passes
GFP_KERNEL to kmalloc().
The patch converts from on_each_cpu() to for_each_cpu(), and then
simplifies things.
diff -rup linux-2.6.16.13-xen/arch/i386/oprofile/xenoprof.c
linux-2.6.16.13-xen.patched-1/arch/i386/oprofile/xenoprof.c
--- linux-2.6.16.13-xen/arch/i386/oprofile/xenoprof.c 2006-05-15
10:32:22.000000000 +0200
+++ linux-2.6.16.13-xen.patched-1/arch/i386/oprofile/xenoprof.c 2006-05-15
10:30:49.000000000 +0200
@@ -141,56 +141,40 @@ xenoprof_ovf_interrupt(int irq, void * d
}
-static void unbind_virq_cpu(void * info)
-{
- int cpu = smp_processor_id();
- if (ovf_irq[cpu] >= 0) {
- unbind_from_irqhandler(ovf_irq[cpu], NULL);
- ovf_irq[cpu] = -1;
- }
-}
-
-
static void unbind_virq(void)
{
- on_each_cpu(unbind_virq_cpu, NULL, 0, 1);
-}
-
-
-int bind_virq_error;
-
-static void bind_virq_cpu(void * info)
-{
- int result;
- int cpu = smp_processor_id();
+ int i;
- result = bind_virq_to_irqhandler(VIRQ_XENOPROF,
- cpu,
- xenoprof_ovf_interrupt,
- SA_INTERRUPT,
- "xenoprof",
- NULL);
-
- if (result<0) {
- bind_virq_error = result;
- printk("xenoprof.c: binding VIRQ_XENOPROF to IRQ failed on CPU "
- "%d\n", cpu);
- } else {
- ovf_irq[cpu] = result;
+ for_each_cpu(i) {
+ if (ovf_irq[i] >= 0) {
+ unbind_from_irqhandler(ovf_irq[i], NULL);
+ ovf_irq[i] = -1;
+ }
}
}
static int bind_virq(void)
{
- bind_virq_error = 0;
- on_each_cpu(bind_virq_cpu, NULL, 0, 1);
- if (bind_virq_error) {
- unbind_virq();
- return bind_virq_error;
- } else {
- return 0;
+ int i, result;
+
+ for_each_cpu(i) {
+ result = bind_virq_to_irqhandler(VIRQ_XENOPROF,
+ i,
+ xenoprof_ovf_interrupt,
+ SA_INTERRUPT,
+ "xenoprof",
+ NULL);
+
+ if (result < 0) {
+ unbind_virq();
+ return result;
+ }
+
+ ovf_irq[i] = result;
}
+
+ return 0;
}
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel
Markus Armbruster
2006-May-15 16:32 UTC
[Xen-devel] [PATCH 2/3] xenoprof fixes: active_domains races
The active_domains code has race conditions:
* oprofile_set_active() calls set_active() method without holding
start_sem. This is clearly wrong, as xenoprof_set_active() makes
several hypercalls. oprofile_start(), for instance, could run in
the middle of xenoprof_set_active().
* adomain_write(), adomain_read() and xenoprof_set_active() access
global active_domains[] and adomains without synchronization. I
went for a simple, obvious fix and created another mutex. Instead,
one could move the shared data into oprof.c and protect it with
start_sem, but that''s more invasive.
diff -rup linux-2.6.16.13-xen.patched-1/drivers/oprofile/oprof.c
linux-2.6.16.13-xen.patched-2/drivers/oprofile/oprof.c
--- linux-2.6.16.13-xen.patched-1/drivers/oprofile/oprof.c 2006-05-15
10:28:11.000000000 +0200
+++ linux-2.6.16.13-xen.patched-2/drivers/oprofile/oprof.c 2006-05-15
10:31:11.000000000 +0200
@@ -42,10 +42,15 @@ extern int active_domains[MAX_OPROF_DOMA
int oprofile_set_active(void)
{
- if (oprofile_ops.set_active)
- return oprofile_ops.set_active(active_domains, adomains);
+ int err;
+
+ if (!oprofile_ops.set_active)
+ return -EINVAL;
- return -EINVAL;
+ down(&start_sem);
+ err = oprofile_ops.set_active(active_domains, adomains);
+ up(&start_sem);
+ return err;
}
int oprofile_setup(void)
diff -rup linux-2.6.16.13-xen.patched-1/drivers/oprofile/oprofile_files.c
linux-2.6.16.13-xen.patched-2/drivers/oprofile/oprofile_files.c
--- linux-2.6.16.13-xen.patched-1/drivers/oprofile/oprofile_files.c 2006-05-15
10:28:11.000000000 +0200
+++ linux-2.6.16.13-xen.patched-2/drivers/oprofile/oprofile_files.c 2006-05-15
10:31:11.000000000 +0200
@@ -128,6 +128,7 @@ static struct file_operations dump_fops
unsigned int adomains = 0;
long active_domains[MAX_OPROF_DOMAINS];
+static DECLARE_MUTEX(adom_sem);
static ssize_t adomain_write(struct file * file, char const __user * buf,
size_t count, loff_t * offset)
@@ -137,6 +138,7 @@ static ssize_t adomain_write(struct file
char * endp = tmpbuf;
int i;
unsigned long val;
+ ssize_t retval = count;
if (*offset)
return -EINVAL;
@@ -150,6 +152,8 @@ static ssize_t adomain_write(struct file
if (copy_from_user(tmpbuf, buf, count))
return -EFAULT;
+ down(&adom_sem);
+
for (i = 0; i < MAX_OPROF_DOMAINS; i++)
active_domains[i] = -1;
adomains = 0;
@@ -165,9 +169,12 @@ static ssize_t adomain_write(struct file
break;
startp = endp;
}
+
if (oprofile_set_active())
- return -EINVAL;
- return count;
+ retval = -EINVAL;
+
+ up(&adom_sem);
+ return retval;
}
static ssize_t adomain_read(struct file * file, char __user * buf,
@@ -176,11 +183,17 @@ static ssize_t adomain_read(struct file
char tmpbuf[TMPBUFSIZE];
size_t len = 0;
int i;
+
+ down(&adom_sem);
+
/* This is all screwed up if we run out of space */
for (i = 0; i < adomains; i++)
len += snprintf(tmpbuf + len, TMPBUFSIZE - len,
"%u ", (unsigned int)active_domains[i]);
len += snprintf(tmpbuf + len, TMPBUFSIZE - len, "\n");
+
+ up(&adom_sem);
+
return simple_read_from_buffer((void __user *)buf, count,
offset, tmpbuf, len);
}
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel
Markus Armbruster
2006-May-15 16:33 UTC
[Xen-devel] [PATCH 3/3] xenoprof fixes: active_domains cleanup
This is a cleanup the code dealing with /dev/oprofile/active_domains:
* Use parameters instead of global variables to pass domain ids
around. Give those globals internal linkage.
* Allocate buffers dynamically to conserve stack space.
* Treat writes with size zero exactly like a write containing no
domain id. Before, zero-sized write was ignored, which is not the
same.
* Parse domain ids as unsigned numbers. Before, the first one was
parsed as signed number.
Because ispunct()-punctuation is ignored between domain ids, signs
are still silently ignored except for the first number. Hmm.
* Make parser accept whitespace as domain separator, because that''s
what you get when reading the file.
* EINVAL on domain ids overflowing domid_t. Before, they were
silently truncated.
* EINVAL on too many domain ids. Before, the excess ones were
silently ignored.
* Reset active domains on failure halfway through setting them.
* Fix potential buffer overflow in adomain_read(). Couldn''t really
happen because buffer was sufficient for current value of
MAX_OPROF_DOMAINS.
diff -rup linux-2.6.16.13-xen.patched-2/arch/i386/oprofile/xenoprof.c
linux-2.6.16.13-xen.patched-3/arch/i386/oprofile/xenoprof.c
--- linux-2.6.16.13-xen.patched-2/arch/i386/oprofile/xenoprof.c 2006-05-15
10:30:49.000000000 +0200
+++ linux-2.6.16.13-xen.patched-3/arch/i386/oprofile/xenoprof.c 2006-05-15
10:31:23.000000000 +0200
@@ -289,9 +289,13 @@ static int xenoprof_set_active(int * act
for (i=0; i<adomains; i++) {
domid = active_domains[i];
+ if (domid != active_domains[i]) {
+ ret = -EINVAL;
+ goto out;
+ }
ret = HYPERVISOR_xenoprof_op(XENOPROF_set_active, &domid);
if (ret)
- return (ret);
+ goto out;
if (active_domains[i] == 0)
set_dom0 = 1;
}
@@ -300,8 +304,11 @@ static int xenoprof_set_active(int * act
domid = 0;
ret = HYPERVISOR_xenoprof_op(XENOPROF_set_active, &domid);
}
-
- active_defined = 1;
+
+out:
+ if (ret)
+ HYPERVISOR_xenoprof_op(XENOPROF_reset_active_list, NULL);
+ active_defined = !ret;
return ret;
}
diff -rup linux-2.6.16.13-xen.patched-2/drivers/oprofile/oprof.c
linux-2.6.16.13-xen.patched-3/drivers/oprofile/oprof.c
--- linux-2.6.16.13-xen.patched-2/drivers/oprofile/oprof.c 2006-05-15
10:31:11.000000000 +0200
+++ linux-2.6.16.13-xen.patched-3/drivers/oprofile/oprof.c 2006-05-15
10:31:44.000000000 +0200
@@ -37,10 +37,7 @@ static DECLARE_MUTEX(start_sem);
*/
static int timer = 0;
-extern unsigned int adomains;
-extern int active_domains[MAX_OPROF_DOMAINS];
-
-int oprofile_set_active(void)
+int oprofile_set_active(int active_domains[], unsigned int adomains)
{
int err;
diff -rup linux-2.6.16.13-xen.patched-2/drivers/oprofile/oprof.h
linux-2.6.16.13-xen.patched-3/drivers/oprofile/oprof.h
--- linux-2.6.16.13-xen.patched-2/drivers/oprofile/oprof.h 2006-05-15
10:28:11.000000000 +0200
+++ linux-2.6.16.13-xen.patched-3/drivers/oprofile/oprof.h 2006-05-15
10:31:23.000000000 +0200
@@ -36,6 +36,8 @@ void oprofile_timer_init(struct oprofile
int oprofile_set_backtrace(unsigned long depth);
-int oprofile_set_active(void);
+#ifdef CONFIG_XEN
+int oprofile_set_active(int active_domains[], unsigned int adomains);
+#endif
#endif /* OPROF_H */
diff -rup linux-2.6.16.13-xen.patched-2/drivers/oprofile/oprofile_files.c
linux-2.6.16.13-xen.patched-3/drivers/oprofile/oprofile_files.c
--- linux-2.6.16.13-xen.patched-2/drivers/oprofile/oprofile_files.c 2006-05-15
10:31:11.000000000 +0200
+++ linux-2.6.16.13-xen.patched-3/drivers/oprofile/oprofile_files.c 2006-05-15
10:31:23.000000000 +0200
@@ -126,52 +126,59 @@ static struct file_operations dump_fops
#define TMPBUFSIZE 512
-unsigned int adomains = 0;
-long active_domains[MAX_OPROF_DOMAINS];
+static unsigned int adomains = 0;
+static int active_domains[MAX_OPROF_DOMAINS + 1];
static DECLARE_MUTEX(adom_sem);
static ssize_t adomain_write(struct file * file, char const __user * buf,
size_t count, loff_t * offset)
{
- char tmpbuf[TMPBUFSIZE];
- char * startp = tmpbuf;
- char * endp = tmpbuf;
+ char *tmpbuf;
+ char *startp, *endp;
int i;
unsigned long val;
ssize_t retval = count;
if (*offset)
return -EINVAL;
- if (!count)
- return 0;
if (count > TMPBUFSIZE - 1)
return -EINVAL;
- memset(tmpbuf, 0x0, TMPBUFSIZE);
+ if (!(tmpbuf = kmalloc(TMPBUFSIZE, GFP_KERNEL)))
+ return -ENOMEM;
- if (copy_from_user(tmpbuf, buf, count))
+ if (copy_from_user(tmpbuf, buf, count)) {
+ kfree(tmpbuf);
return -EFAULT;
-
- down(&adom_sem);
+ }
+ tmpbuf[count] = 0;
- for (i = 0; i < MAX_OPROF_DOMAINS; i++)
- active_domains[i] = -1;
- adomains = 0;
+ down(&adom_sem);
- while (1) {
- val = simple_strtol(startp, &endp, 0);
+ startp = tmpbuf;
+ /* Parse one more than MAX_OPROF_DOMAINS, for easy error checking */
+ for (i = 0; i <= MAX_OPROF_DOMAINS; i++) {
+ val = simple_strtoul(startp, &endp, 0);
if (endp == startp)
break;
- while (ispunct(*endp))
+ while (ispunct(*endp) || isspace(*endp))
endp++;
- active_domains[adomains++] = val;
- if (adomains >= MAX_OPROF_DOMAINS)
- break;
+ active_domains[i] = val;
+ if (active_domains[i] != val)
+ /* Overflow, force error below */
+ i = MAX_OPROF_DOMAINS + 1;
startp = endp;
}
+ /* Force error on trailing junk */
+ adomains = *startp ? MAX_OPROF_DOMAINS + 1 : i;
- if (oprofile_set_active())
+ kfree(tmpbuf);
+
+ if (adomains > MAX_OPROF_DOMAINS
+ || oprofile_set_active(active_domains, adomains)) {
+ adomains = 0;
retval = -EINVAL;
+ }
up(&adom_sem);
return retval;
@@ -180,22 +187,31 @@ static ssize_t adomain_write(struct file
static ssize_t adomain_read(struct file * file, char __user * buf,
size_t count, loff_t * offset)
{
- char tmpbuf[TMPBUFSIZE];
- size_t len = 0;
+ char * tmpbuf;
+ size_t len;
int i;
+ ssize_t retval;
+
+ if (!(tmpbuf = kmalloc(TMPBUFSIZE, GFP_KERNEL)))
+ return -ENOMEM;
down(&adom_sem);
- /* This is all screwed up if we run out of space */
- for (i = 0; i < adomains; i++)
- len += snprintf(tmpbuf + len, TMPBUFSIZE - len,
- "%u ", (unsigned int)active_domains[i]);
- len += snprintf(tmpbuf + len, TMPBUFSIZE - len, "\n");
+ len = 0;
+ for (i = 0; i < adomains; i++)
+ len += snprintf(tmpbuf + len,
+ len < TMPBUFSIZE ? TMPBUFSIZE - len : 0,
+ "%u ", active_domains[i]);
+ WARN_ON(len > TMPBUFSIZE);
+ if (len != 0 && len <= TMPBUFSIZE)
+ tmpbuf[len-1] = ''\n'';
up(&adom_sem);
- return simple_read_from_buffer((void __user *)buf, count,
- offset, tmpbuf, len);
+ retval = simple_read_from_buffer(buf, count, offset, tmpbuf, len);
+
+ kfree(tmpbuf);
+ return retval;
}
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel
These all look good to me. They fix some very bad bugs, Can you please provide a signed-off-by line, however? -- Keir On 15 May 2006, at 17:31, Markus Armbruster wrote:> These patches address issues in the kernel part of xenoprof: > > * Ill-advised use of on_each_cpu() can lead to sleep with interrupts > disabled. > > * Race conditions in active_domains code. > > * Cleanup of active_domains code. > > Comments welcome. > > _______________________________________________ > Xen-devel mailing list > Xen-devel@lists.xensource.com > http://lists.xensource.com/xen-devel_______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Keir Fraser <Keir.Fraser@cl.cam.ac.uk> writes:> These all look good to me. They fix some very bad bugs, Can you please > provide a signed-off-by line, however?Oops, sorry. Do you want me to resubmit with that? Signed-off-by: Markus Armbruster <armbru@redhat.com> _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
On 15 May 2006, at 18:14, Markus Armbruster wrote:>> These all look good to me. They fix some very bad bugs, Can you please >> provide a signed-off-by line, however? > > Oops, sorry. Do you want me to resubmit with that? > > Signed-off-by: Markus Armbruster <armbru@redhat.com>Yeah, it''s supposed to be in the email with the patch. Just resend them all. -- Keir _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Markus Armbruster
2006-May-15 17:33 UTC
[Xen-devel] Re: [PATCH 1/3] xenoprof fixes: sleep with interrupts disabled
Ill-advised use of on_each_cpu() can lead to sleep with interrupts
disabled. This is best explained with a backtrace:
BUG: sleeping function called from invalid context at
/home/armbru/linux-2.6.tip-xen-quintela.hg/mm/slab.c:2783
in_atomic():0, irqs_disabled():1
[<c0104f36>] show_trace+0x13/0x15
[<c0105439>] dump_stack+0x18/0x1c
[<c01161ac>] __might_sleep+0x9f/0xa7
[<c0158823>] __kmalloc+0x65/0x110
[<c018e01d>] proc_create+0x8d/0xe2
[<c018e12d>] proc_mkdir_mode+0x1a/0x4d
[<c018e173>] proc_mkdir+0x13/0x15
[<c013de9b>] register_handler_proc+0x90/0x9e
[<c013d729>] setup_irq+0xdf/0xf5
[<c013d7a9>] request_irq+0x6a/0x8a
[<c0231817>] bind_virq_to_irqhandler+0xe3/0x101
[<f4c83b02>] bind_virq_cpu+0x28/0x62 [oprofile]
[<c0121453>] on_each_cpu+0x36/0x5d
[<f4c83c3b>] xenoprof_setup+0x22/0x14a [oprofile]
[<f4c820bf>] oprofile_setup+0x45/0x8b [oprofile]
[<f4c82fa3>] event_buffer_open+0x3e/0x62 [oprofile]
[<c0159eda>] __dentry_open+0xc7/0x1b0
[<c015a034>] nameidata_to_filp+0x20/0x34
[<c015a078>] do_filp_open+0x30/0x39
[<c015afe6>] do_sys_open+0x40/0xb0
[<c015b07f>] sys_open+0x13/0x15
[<c01048cf>] syscall_call+0x7/0xb
on_each_cpu() disables interrupts. proc_create() calls passes
GFP_KERNEL to kmalloc().
The patch converts from on_each_cpu() to for_each_cpu(), and then
simplifies things.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
diff -rup linux-2.6.16.13-xen/arch/i386/oprofile/xenoprof.c
linux-2.6.16.13-xen.patched-1/arch/i386/oprofile/xenoprof.c
--- linux-2.6.16.13-xen/arch/i386/oprofile/xenoprof.c 2006-05-15
10:32:22.000000000 +0200
+++ linux-2.6.16.13-xen.patched-1/arch/i386/oprofile/xenoprof.c 2006-05-15
10:30:49.000000000 +0200
@@ -141,56 +141,40 @@ xenoprof_ovf_interrupt(int irq, void * d
}
-static void unbind_virq_cpu(void * info)
-{
- int cpu = smp_processor_id();
- if (ovf_irq[cpu] >= 0) {
- unbind_from_irqhandler(ovf_irq[cpu], NULL);
- ovf_irq[cpu] = -1;
- }
-}
-
-
static void unbind_virq(void)
{
- on_each_cpu(unbind_virq_cpu, NULL, 0, 1);
-}
-
-
-int bind_virq_error;
-
-static void bind_virq_cpu(void * info)
-{
- int result;
- int cpu = smp_processor_id();
+ int i;
- result = bind_virq_to_irqhandler(VIRQ_XENOPROF,
- cpu,
- xenoprof_ovf_interrupt,
- SA_INTERRUPT,
- "xenoprof",
- NULL);
-
- if (result<0) {
- bind_virq_error = result;
- printk("xenoprof.c: binding VIRQ_XENOPROF to IRQ failed on CPU "
- "%d\n", cpu);
- } else {
- ovf_irq[cpu] = result;
+ for_each_cpu(i) {
+ if (ovf_irq[i] >= 0) {
+ unbind_from_irqhandler(ovf_irq[i], NULL);
+ ovf_irq[i] = -1;
+ }
}
}
static int bind_virq(void)
{
- bind_virq_error = 0;
- on_each_cpu(bind_virq_cpu, NULL, 0, 1);
- if (bind_virq_error) {
- unbind_virq();
- return bind_virq_error;
- } else {
- return 0;
+ int i, result;
+
+ for_each_cpu(i) {
+ result = bind_virq_to_irqhandler(VIRQ_XENOPROF,
+ i,
+ xenoprof_ovf_interrupt,
+ SA_INTERRUPT,
+ "xenoprof",
+ NULL);
+
+ if (result < 0) {
+ unbind_virq();
+ return result;
+ }
+
+ ovf_irq[i] = result;
}
+
+ return 0;
}
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel
Markus Armbruster
2006-May-15 17:34 UTC
[Xen-devel] Re: [PATCH 2/3] xenoprof fixes: active_domains races
The active_domains code has race conditions:
* oprofile_set_active() calls set_active() method without holding
start_sem. This is clearly wrong, as xenoprof_set_active() makes
several hypercalls. oprofile_start(), for instance, could run in
the middle of xenoprof_set_active().
* adomain_write(), adomain_read() and xenoprof_set_active() access
global active_domains[] and adomains without synchronization. I
went for a simple, obvious fix and created another mutex. Instead,
one could move the shared data into oprof.c and protect it with
start_sem, but that''s more invasive.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
diff -rup linux-2.6.16.13-xen.patched-1/drivers/oprofile/oprof.c
linux-2.6.16.13-xen.patched-2/drivers/oprofile/oprof.c
--- linux-2.6.16.13-xen.patched-1/drivers/oprofile/oprof.c 2006-05-15
10:28:11.000000000 +0200
+++ linux-2.6.16.13-xen.patched-2/drivers/oprofile/oprof.c 2006-05-15
10:31:11.000000000 +0200
@@ -42,10 +42,15 @@ extern int active_domains[MAX_OPROF_DOMA
int oprofile_set_active(void)
{
- if (oprofile_ops.set_active)
- return oprofile_ops.set_active(active_domains, adomains);
+ int err;
+
+ if (!oprofile_ops.set_active)
+ return -EINVAL;
- return -EINVAL;
+ down(&start_sem);
+ err = oprofile_ops.set_active(active_domains, adomains);
+ up(&start_sem);
+ return err;
}
int oprofile_setup(void)
diff -rup linux-2.6.16.13-xen.patched-1/drivers/oprofile/oprofile_files.c
linux-2.6.16.13-xen.patched-2/drivers/oprofile/oprofile_files.c
--- linux-2.6.16.13-xen.patched-1/drivers/oprofile/oprofile_files.c 2006-05-15
10:28:11.000000000 +0200
+++ linux-2.6.16.13-xen.patched-2/drivers/oprofile/oprofile_files.c 2006-05-15
10:31:11.000000000 +0200
@@ -128,6 +128,7 @@ static struct file_operations dump_fops
unsigned int adomains = 0;
long active_domains[MAX_OPROF_DOMAINS];
+static DECLARE_MUTEX(adom_sem);
static ssize_t adomain_write(struct file * file, char const __user * buf,
size_t count, loff_t * offset)
@@ -137,6 +138,7 @@ static ssize_t adomain_write(struct file
char * endp = tmpbuf;
int i;
unsigned long val;
+ ssize_t retval = count;
if (*offset)
return -EINVAL;
@@ -150,6 +152,8 @@ static ssize_t adomain_write(struct file
if (copy_from_user(tmpbuf, buf, count))
return -EFAULT;
+ down(&adom_sem);
+
for (i = 0; i < MAX_OPROF_DOMAINS; i++)
active_domains[i] = -1;
adomains = 0;
@@ -165,9 +169,12 @@ static ssize_t adomain_write(struct file
break;
startp = endp;
}
+
if (oprofile_set_active())
- return -EINVAL;
- return count;
+ retval = -EINVAL;
+
+ up(&adom_sem);
+ return retval;
}
static ssize_t adomain_read(struct file * file, char __user * buf,
@@ -176,11 +183,17 @@ static ssize_t adomain_read(struct file
char tmpbuf[TMPBUFSIZE];
size_t len = 0;
int i;
+
+ down(&adom_sem);
+
/* This is all screwed up if we run out of space */
for (i = 0; i < adomains; i++)
len += snprintf(tmpbuf + len, TMPBUFSIZE - len,
"%u ", (unsigned int)active_domains[i]);
len += snprintf(tmpbuf + len, TMPBUFSIZE - len, "\n");
+
+ up(&adom_sem);
+
return simple_read_from_buffer((void __user *)buf, count,
offset, tmpbuf, len);
}
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel
Markus Armbruster
2006-May-15 17:34 UTC
[Xen-devel] Re: [PATCH 3/3] xenoprof fixes: active_domains cleanup
This is a cleanup the code dealing with /dev/oprofile/active_domains:
* Use parameters instead of global variables to pass domain ids
around. Give those globals internal linkage.
* Allocate buffers dynamically to conserve stack space.
* Treat writes with size zero exactly like a write containing no
domain id. Before, zero-sized write was ignored, which is not the
same.
* Parse domain ids as unsigned numbers. Before, the first one was
parsed as signed number.
Because ispunct()-punctuation is ignored between domain ids, signs
are still silently ignored except for the first number. Hmm.
* Make parser accept whitespace as domain separator, because that''s
what you get when reading the file.
* EINVAL on domain ids overflowing domid_t. Before, they were
silently truncated.
* EINVAL on too many domain ids. Before, the excess ones were
silently ignored.
* Reset active domains on failure halfway through setting them.
* Fix potential buffer overflow in adomain_read(). Couldn''t really
happen because buffer was sufficient for current value of
MAX_OPROF_DOMAINS.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
diff -rup linux-2.6.16.13-xen.patched-2/arch/i386/oprofile/xenoprof.c
linux-2.6.16.13-xen.patched-3/arch/i386/oprofile/xenoprof.c
--- linux-2.6.16.13-xen.patched-2/arch/i386/oprofile/xenoprof.c 2006-05-15
10:30:49.000000000 +0200
+++ linux-2.6.16.13-xen.patched-3/arch/i386/oprofile/xenoprof.c 2006-05-15
10:31:23.000000000 +0200
@@ -289,9 +289,13 @@ static int xenoprof_set_active(int * act
for (i=0; i<adomains; i++) {
domid = active_domains[i];
+ if (domid != active_domains[i]) {
+ ret = -EINVAL;
+ goto out;
+ }
ret = HYPERVISOR_xenoprof_op(XENOPROF_set_active, &domid);
if (ret)
- return (ret);
+ goto out;
if (active_domains[i] == 0)
set_dom0 = 1;
}
@@ -300,8 +304,11 @@ static int xenoprof_set_active(int * act
domid = 0;
ret = HYPERVISOR_xenoprof_op(XENOPROF_set_active, &domid);
}
-
- active_defined = 1;
+
+out:
+ if (ret)
+ HYPERVISOR_xenoprof_op(XENOPROF_reset_active_list, NULL);
+ active_defined = !ret;
return ret;
}
diff -rup linux-2.6.16.13-xen.patched-2/drivers/oprofile/oprof.c
linux-2.6.16.13-xen.patched-3/drivers/oprofile/oprof.c
--- linux-2.6.16.13-xen.patched-2/drivers/oprofile/oprof.c 2006-05-15
10:31:11.000000000 +0200
+++ linux-2.6.16.13-xen.patched-3/drivers/oprofile/oprof.c 2006-05-15
10:31:44.000000000 +0200
@@ -37,10 +37,7 @@ static DECLARE_MUTEX(start_sem);
*/
static int timer = 0;
-extern unsigned int adomains;
-extern int active_domains[MAX_OPROF_DOMAINS];
-
-int oprofile_set_active(void)
+int oprofile_set_active(int active_domains[], unsigned int adomains)
{
int err;
diff -rup linux-2.6.16.13-xen.patched-2/drivers/oprofile/oprof.h
linux-2.6.16.13-xen.patched-3/drivers/oprofile/oprof.h
--- linux-2.6.16.13-xen.patched-2/drivers/oprofile/oprof.h 2006-05-15
10:28:11.000000000 +0200
+++ linux-2.6.16.13-xen.patched-3/drivers/oprofile/oprof.h 2006-05-15
10:31:23.000000000 +0200
@@ -36,6 +36,8 @@ void oprofile_timer_init(struct oprofile
int oprofile_set_backtrace(unsigned long depth);
-int oprofile_set_active(void);
+#ifdef CONFIG_XEN
+int oprofile_set_active(int active_domains[], unsigned int adomains);
+#endif
#endif /* OPROF_H */
diff -rup linux-2.6.16.13-xen.patched-2/drivers/oprofile/oprofile_files.c
linux-2.6.16.13-xen.patched-3/drivers/oprofile/oprofile_files.c
--- linux-2.6.16.13-xen.patched-2/drivers/oprofile/oprofile_files.c 2006-05-15
10:31:11.000000000 +0200
+++ linux-2.6.16.13-xen.patched-3/drivers/oprofile/oprofile_files.c 2006-05-15
10:31:23.000000000 +0200
@@ -126,52 +126,59 @@ static struct file_operations dump_fops
#define TMPBUFSIZE 512
-unsigned int adomains = 0;
-long active_domains[MAX_OPROF_DOMAINS];
+static unsigned int adomains = 0;
+static int active_domains[MAX_OPROF_DOMAINS + 1];
static DECLARE_MUTEX(adom_sem);
static ssize_t adomain_write(struct file * file, char const __user * buf,
size_t count, loff_t * offset)
{
- char tmpbuf[TMPBUFSIZE];
- char * startp = tmpbuf;
- char * endp = tmpbuf;
+ char *tmpbuf;
+ char *startp, *endp;
int i;
unsigned long val;
ssize_t retval = count;
if (*offset)
return -EINVAL;
- if (!count)
- return 0;
if (count > TMPBUFSIZE - 1)
return -EINVAL;
- memset(tmpbuf, 0x0, TMPBUFSIZE);
+ if (!(tmpbuf = kmalloc(TMPBUFSIZE, GFP_KERNEL)))
+ return -ENOMEM;
- if (copy_from_user(tmpbuf, buf, count))
+ if (copy_from_user(tmpbuf, buf, count)) {
+ kfree(tmpbuf);
return -EFAULT;
-
- down(&adom_sem);
+ }
+ tmpbuf[count] = 0;
- for (i = 0; i < MAX_OPROF_DOMAINS; i++)
- active_domains[i] = -1;
- adomains = 0;
+ down(&adom_sem);
- while (1) {
- val = simple_strtol(startp, &endp, 0);
+ startp = tmpbuf;
+ /* Parse one more than MAX_OPROF_DOMAINS, for easy error checking */
+ for (i = 0; i <= MAX_OPROF_DOMAINS; i++) {
+ val = simple_strtoul(startp, &endp, 0);
if (endp == startp)
break;
- while (ispunct(*endp))
+ while (ispunct(*endp) || isspace(*endp))
endp++;
- active_domains[adomains++] = val;
- if (adomains >= MAX_OPROF_DOMAINS)
- break;
+ active_domains[i] = val;
+ if (active_domains[i] != val)
+ /* Overflow, force error below */
+ i = MAX_OPROF_DOMAINS + 1;
startp = endp;
}
+ /* Force error on trailing junk */
+ adomains = *startp ? MAX_OPROF_DOMAINS + 1 : i;
- if (oprofile_set_active())
+ kfree(tmpbuf);
+
+ if (adomains > MAX_OPROF_DOMAINS
+ || oprofile_set_active(active_domains, adomains)) {
+ adomains = 0;
retval = -EINVAL;
+ }
up(&adom_sem);
return retval;
@@ -180,22 +187,31 @@ static ssize_t adomain_write(struct file
static ssize_t adomain_read(struct file * file, char __user * buf,
size_t count, loff_t * offset)
{
- char tmpbuf[TMPBUFSIZE];
- size_t len = 0;
+ char * tmpbuf;
+ size_t len;
int i;
+ ssize_t retval;
+
+ if (!(tmpbuf = kmalloc(TMPBUFSIZE, GFP_KERNEL)))
+ return -ENOMEM;
down(&adom_sem);
- /* This is all screwed up if we run out of space */
- for (i = 0; i < adomains; i++)
- len += snprintf(tmpbuf + len, TMPBUFSIZE - len,
- "%u ", (unsigned int)active_domains[i]);
- len += snprintf(tmpbuf + len, TMPBUFSIZE - len, "\n");
+ len = 0;
+ for (i = 0; i < adomains; i++)
+ len += snprintf(tmpbuf + len,
+ len < TMPBUFSIZE ? TMPBUFSIZE - len : 0,
+ "%u ", active_domains[i]);
+ WARN_ON(len > TMPBUFSIZE);
+ if (len != 0 && len <= TMPBUFSIZE)
+ tmpbuf[len-1] = ''\n'';
up(&adom_sem);
- return simple_read_from_buffer((void __user *)buf, count,
- offset, tmpbuf, len);
+ retval = simple_read_from_buffer(buf, count, offset, tmpbuf, len);
+
+ kfree(tmpbuf);
+ return retval;
}
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel
Chris Wright
2006-May-15 18:53 UTC
Re: [Xen-devel] [PATCH 2/3] xenoprof fixes: active_domains races
* Markus Armbruster (armbru@redhat.com) wrote:> --- linux-2.6.16.13-xen.patched-1/drivers/oprofile/oprofile_files.c 2006-05-15 10:28:11.000000000 +0200 > +++ linux-2.6.16.13-xen.patched-2/drivers/oprofile/oprofile_files.c 2006-05-15 10:31:11.000000000 +0200 > @@ -128,6 +128,7 @@ static struct file_operations dump_fops > > unsigned int adomains = 0; > long active_domains[MAX_OPROF_DOMAINS]; > +static DECLARE_MUTEX(adom_sem);Sorry, didn''t mention this earlier. Please use new mutex code here, smth like: s/DECLARE_MUTEX(adom_sec)/DEFINE_MUTEX(adomain_mutex)/ s/down(&adom_sem)/mutex_lock(&adomain_mutex)/ s/up(&adom_sem)/mutex_unlock(&admoain_mutex)/ thanks, -chris _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Markus Armbruster
2006-May-15 19:15 UTC
Re: [Xen-devel] [PATCH 2/3] xenoprof fixes: active_domains races
Chris Wright <chrisw@sous-sol.org> writes:> * Markus Armbruster (armbru@redhat.com) wrote: >> --- linux-2.6.16.13-xen.patched-1/drivers/oprofile/oprofile_files.c 2006-05-15 10:28:11.000000000 +0200 >> +++ linux-2.6.16.13-xen.patched-2/drivers/oprofile/oprofile_files.c 2006-05-15 10:31:11.000000000 +0200 >> @@ -128,6 +128,7 @@ static struct file_operations dump_fops >> >> unsigned int adomains = 0; >> long active_domains[MAX_OPROF_DOMAINS]; >> +static DECLARE_MUTEX(adom_sem); > > Sorry, didn''t mention this earlier. Please use new mutex code here, > smth like: > > s/DECLARE_MUTEX(adom_sec)/DEFINE_MUTEX(adomain_mutex)/ > s/down(&adom_sem)/mutex_lock(&adomain_mutex)/ > s/up(&adom_sem)/mutex_unlock(&admoain_mutex)/ > > thanks, > -chrisWhat about buffer_sem in drivers/oprofile/event_buffer.c and start_sem in drivers/oprofile/oprof.c? Want me to submit a patch to convert all three? _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Santos, Jose Renato G
2006-May-15 21:51 UTC
RE: [Xen-devel] [PATCH 2/3] xenoprof fixes: active_domains races
>> > Sorry, didn''t mention this earlier. Please use new mutex >> code here, >> > smth like: >> > >> > s/DECLARE_MUTEX(adom_sec)/DEFINE_MUTEX(adomain_mutex)/ >> > s/down(&adom_sem)/mutex_lock(&adomain_mutex)/ >> > s/up(&adom_sem)/mutex_unlock(&admoain_mutex)/ >> > >> > thanks, >> > -chris >> >> What about buffer_sem in drivers/oprofile/event_buffer.c and >> start_sem in drivers/oprofile/oprof.c? Want me to submit a >> patch to convert all three? >>I think we should minimize changes to generic oprofile code (in drivers/oprofile) to minimize divergence from main stream linux. For this reason I don''t think we should touch buffer_sem and start_sem. Renato _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Chris Wright
2006-May-16 07:23 UTC
Re: [Xen-devel] [PATCH 2/3] xenoprof fixes: active_domains races
* Santos, Jose Renato G (joserenato.santos@hp.com) wrote:> >> What about buffer_sem in drivers/oprofile/event_buffer.c and > >> start_sem in drivers/oprofile/oprof.c? Want me to submit a > >> patch to convert all three? > > I think we should minimize changes to generic oprofile code > (in drivers/oprofile) to minimize divergence from main stream linux. > For this reason I don''t think we should touch buffer_sem and > start_sem.Well, you can certainly just send bits like that upstream. You never know, they might even appreciate the updates. thanks, -chris _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Keir Fraser
2006-May-16 07:40 UTC
Re: [Xen-devel] [PATCH 2/3] xenoprof fixes: active_domains races
On 15 May 2006, at 22:51, Santos, Jose Renato G wrote:>>> What about buffer_sem in drivers/oprofile/event_buffer.c and >>> start_sem in drivers/oprofile/oprof.c? Want me to submit a >>> patch to convert all three? >>> > > I think we should minimize changes to generic oprofile code > (in drivers/oprofile) to minimize divergence from main stream linux. > For this reason I don''t think we should touch buffer_sem and > start_sem.Absolutely. If you clean those up the patches should go to the oprofile maintainers and lkml, not us. -- Keir _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Keir Fraser
2006-May-16 08:06 UTC
Re: [Xen-devel] Re: [PATCH 1/3] xenoprof fixes: sleep with interrupts disabled
On 15 May 2006, at 18:33, Markus Armbruster wrote:> on_each_cpu() disables interrupts. proc_create() calls passes > GFP_KERNEL to kmalloc(). > > The patch converts from on_each_cpu() to for_each_cpu(), and then > simplifies things. > > Signed-off-by: Markus Armbruster <armbru@redhat.com>Applied, thanks. -- Keir _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Keir Fraser
2006-May-16 08:09 UTC
Re: [Xen-devel] Re: [PATCH 2/3] xenoprof fixes: active_domains races
On 15 May 2006, at 18:34, Markus Armbruster wrote:> The active_domains code has race conditions: > > * oprofile_set_active() calls set_active() method without holding > start_sem. This is clearly wrong, as xenoprof_set_active() makes > several hypercalls. oprofile_start(), for instance, could run in > the middle of xenoprof_set_active(). > > * adomain_write(), adomain_read() and xenoprof_set_active() access > global active_domains[] and adomains without synchronization. I > went for a simple, obvious fix and created another mutex. Instead, > one could move the shared data into oprof.c and protect it with > start_sem, but that''s more invasive. > > Signed-off-by: Markus Armbruster <armbru@redhat.com>Apart from updating to use the new mutex operations, patches 2 and 3 of your submitted set should be applied to patches/linux-2.6.16.13/xenoprof-generic.patch (yes, they need to be a patch of patch: sorry about that!). However, feel free to submit one mega-patch that merges both patches into one patch-of-a-patch. -- Keir _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Markus Armbruster
2006-May-16 09:47 UTC
Re: [Xen-devel] Re: [PATCH 2/3] xenoprof fixes: active_domains races
Keir Fraser <Keir.Fraser@cl.cam.ac.uk> writes: [...]> Apart from updating to use the new mutex operations, patches 2 and 3 > of your submitted set should be applied to > patches/linux-2.6.16.13/xenoprof-generic.patch (yes, they need to be a > patch of patch: sorry about that!). However, feel free to submit one > mega-patch that merges both patches into one patch-of-a-patch. > > -- KeirIs it okay to include the conversion to mutex in xen-specific code? There''s machinery to go from sparse tree + patches to full tree (make prep-kernels). Is there a way to propagate changes from full tree pack to sparse tree + patches, where hg diff takes care of creating patchfiles? _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Keir Fraser
2006-May-16 09:48 UTC
Re: [Xen-devel] Re: [PATCH 2/3] xenoprof fixes: active_domains races
On 16 May 2006, at 10:47, Markus Armbruster wrote:> Is it okay to include the conversion to mutex in xen-specific code?Any semaphores that were added by the xenoprofile patches should be changed to mutexes. The rest should be left alone.> There''s machinery to go from sparse tree + patches to full tree (make > prep-kernels). Is there a way to propagate changes from full tree > pack to sparse tree + patches, where hg diff takes care of creating > patchfiles?Not as far as I know. I touch them infrequently enough that when I do I simply re-create the patches manually. If you want, provide a single patch in the same form as your two previous ones then I''ll turn it into patch-of-a-patch format and check it in. -- Keir _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Markus Armbruster
2006-May-16 11:47 UTC
Re: [Xen-devel] Re: [PATCH 2/3] xenoprof fixes: active_domains races
Keir Fraser <Keir.Fraser@cl.cam.ac.uk> writes:> On 16 May 2006, at 10:47, Markus Armbruster wrote: > >> Is it okay to include the conversion to mutex in xen-specific code? > > Any semaphores that were added by the xenoprofile patches should be > changed to mutexes. The rest should be left alone.Done. Patch for the rest just went to lkml.>> There''s machinery to go from sparse tree + patches to full tree (make >> prep-kernels). Is there a way to propagate changes from full tree >> pack to sparse tree + patches, where hg diff takes care of creating >> patchfiles? > > Not as far as I know. I touch them infrequently enough that when I do > I simply re-create the patches manually. > > If you want, provide a single patch in the same form as your two > previous ones then I''ll turn it into patch-of-a-patch format and check > it in.On its way. Thanks! _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Markus Armbruster
2006-May-16 11:48 UTC
[Xen-devel] [PATCH] xenoprof fixes: active_domains races & cleanup
The active_domains code has race conditions:
* oprofile_set_active() calls set_active() method without holding
start_sem. This is clearly wrong, as xenoprof_set_active() makes
several hypercalls. oprofile_start(), for instance, could run in
the middle of xenoprof_set_active().
* adomain_write(), adomain_read() and xenoprof_set_active() access
global active_domains[] and adomains without synchronization. I
went for a simple, obvious fix and created another mutex. Instead,
one could move the shared data into oprof.c and protect it with
start_sem, but that''s more invasive.
Also clean up the code dealing with /dev/oprofile/active_domains:
* Use parameters instead of global variables to pass domain ids
around. Give those globals internal linkage.
* Allocate buffers dynamically to conserve stack space.
* Treat writes with size zero exactly like a write containing no
domain id. Before, zero-sized write was ignored, which is not the
same.
* Parse domain ids as unsigned numbers. Before, the first one was
parsed as signed number.
Because ispunct()-punctuation is ignored between domain ids, signs
are still silently ignored except for the first number. Hmm.
* Make parser accept whitespace as domain separator, because that''s
what you get when reading the file.
* EINVAL on domain ids overflowing domid_t. Before, they were
silently truncated.
* EINVAL on too many domain ids. Before, the excess ones were
silently ignored.
* Reset active domains on failure halfway through setting them.
* Fix potential buffer overflow in adomain_read(). Couldn''t really
happen because buffer was sufficient for current value of
MAX_OPROF_DOMAINS.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
diff -x ''*~'' -rup
linux-2.6.16.13-xen.patched-1/arch/i386/oprofile/xenoprof.c
linux-2.6.16.13-xen.patched-4/arch/i386/oprofile/xenoprof.c
--- linux-2.6.16.13-xen.patched-1/arch/i386/oprofile/xenoprof.c 2006-05-15
10:30:49.000000000 +0200
+++ linux-2.6.16.13-xen.patched-4/arch/i386/oprofile/xenoprof.c 2006-05-15
10:31:23.000000000 +0200
@@ -289,9 +289,13 @@ static int xenoprof_set_active(int * act
for (i=0; i<adomains; i++) {
domid = active_domains[i];
+ if (domid != active_domains[i]) {
+ ret = -EINVAL;
+ goto out;
+ }
ret = HYPERVISOR_xenoprof_op(XENOPROF_set_active, &domid);
if (ret)
- return (ret);
+ goto out;
if (active_domains[i] == 0)
set_dom0 = 1;
}
@@ -300,8 +304,11 @@ static int xenoprof_set_active(int * act
domid = 0;
ret = HYPERVISOR_xenoprof_op(XENOPROF_set_active, &domid);
}
-
- active_defined = 1;
+
+out:
+ if (ret)
+ HYPERVISOR_xenoprof_op(XENOPROF_reset_active_list, NULL);
+ active_defined = !ret;
return ret;
}
diff -x ''*~'' -rup
linux-2.6.16.13-xen.patched-1/drivers/oprofile/oprof.c
linux-2.6.16.13-xen.patched-4/drivers/oprofile/oprof.c
--- linux-2.6.16.13-xen.patched-1/drivers/oprofile/oprof.c 2006-05-15
10:28:11.000000000 +0200
+++ linux-2.6.16.13-xen.patched-4/drivers/oprofile/oprof.c 2006-05-15
10:31:44.000000000 +0200
@@ -37,15 +37,17 @@ static DECLARE_MUTEX(start_sem);
*/
static int timer = 0;
-extern unsigned int adomains;
-extern int active_domains[MAX_OPROF_DOMAINS];
-
-int oprofile_set_active(void)
+int oprofile_set_active(int active_domains[], unsigned int adomains)
{
- if (oprofile_ops.set_active)
- return oprofile_ops.set_active(active_domains, adomains);
+ int err;
+
+ if (!oprofile_ops.set_active)
+ return -EINVAL;
- return -EINVAL;
+ down(&start_sem);
+ err = oprofile_ops.set_active(active_domains, adomains);
+ up(&start_sem);
+ return err;
}
int oprofile_setup(void)
diff -x ''*~'' -rup
linux-2.6.16.13-xen.patched-1/drivers/oprofile/oprof.h
linux-2.6.16.13-xen.patched-4/drivers/oprofile/oprof.h
--- linux-2.6.16.13-xen.patched-1/drivers/oprofile/oprof.h 2006-05-15
10:28:11.000000000 +0200
+++ linux-2.6.16.13-xen.patched-4/drivers/oprofile/oprof.h 2006-05-16
13:32:42.000000000 +0200
@@ -36,6 +36,6 @@ void oprofile_timer_init(struct oprofile
int oprofile_set_backtrace(unsigned long depth);
-int oprofile_set_active(void);
+int oprofile_set_active(int active_domains[], unsigned int adomains);
#endif /* OPROF_H */
diff -x ''*~'' -rup
linux-2.6.16.13-xen.patched-1/drivers/oprofile/oprofile_files.c
linux-2.6.16.13-xen.patched-4/drivers/oprofile/oprofile_files.c
--- linux-2.6.16.13-xen.patched-1/drivers/oprofile/oprofile_files.c 2006-05-15
10:28:11.000000000 +0200
+++ linux-2.6.16.13-xen.patched-4/drivers/oprofile/oprofile_files.c 2006-05-16
13:42:58.000000000 +0200
@@ -126,63 +126,92 @@ static struct file_operations dump_fops
#define TMPBUFSIZE 512
-unsigned int adomains = 0;
-long active_domains[MAX_OPROF_DOMAINS];
+static unsigned int adomains = 0;
+static int active_domains[MAX_OPROF_DOMAINS + 1];
+static DEFINE_MUTEX(adom_mutex);
static ssize_t adomain_write(struct file * file, char const __user * buf,
size_t count, loff_t * offset)
{
- char tmpbuf[TMPBUFSIZE];
- char * startp = tmpbuf;
- char * endp = tmpbuf;
+ char *tmpbuf;
+ char *startp, *endp;
int i;
unsigned long val;
+ ssize_t retval = count;
if (*offset)
return -EINVAL;
- if (!count)
- return 0;
if (count > TMPBUFSIZE - 1)
return -EINVAL;
- memset(tmpbuf, 0x0, TMPBUFSIZE);
+ if (!(tmpbuf = kmalloc(TMPBUFSIZE, GFP_KERNEL)))
+ return -ENOMEM;
- if (copy_from_user(tmpbuf, buf, count))
+ if (copy_from_user(tmpbuf, buf, count)) {
+ kfree(tmpbuf);
return -EFAULT;
-
- for (i = 0; i < MAX_OPROF_DOMAINS; i++)
- active_domains[i] = -1;
- adomains = 0;
+ }
+ tmpbuf[count] = 0;
- while (1) {
- val = simple_strtol(startp, &endp, 0);
+ mutex_lock(&adom_mutex);
+
+ startp = tmpbuf;
+ /* Parse one more than MAX_OPROF_DOMAINS, for easy error checking */
+ for (i = 0; i <= MAX_OPROF_DOMAINS; i++) {
+ val = simple_strtoul(startp, &endp, 0);
if (endp == startp)
break;
- while (ispunct(*endp))
+ while (ispunct(*endp) || isspace(*endp))
endp++;
- active_domains[adomains++] = val;
- if (adomains >= MAX_OPROF_DOMAINS)
- break;
+ active_domains[i] = val;
+ if (active_domains[i] != val)
+ /* Overflow, force error below */
+ i = MAX_OPROF_DOMAINS + 1;
startp = endp;
}
- if (oprofile_set_active())
- return -EINVAL;
- return count;
+ /* Force error on trailing junk */
+ adomains = *startp ? MAX_OPROF_DOMAINS + 1 : i;
+
+ kfree(tmpbuf);
+
+ if (adomains > MAX_OPROF_DOMAINS
+ || oprofile_set_active(active_domains, adomains)) {
+ adomains = 0;
+ retval = -EINVAL;
+ }
+
+ mutex_unlock(&adom_mutex);
+ return retval;
}
static ssize_t adomain_read(struct file * file, char __user * buf,
size_t count, loff_t * offset)
{
- char tmpbuf[TMPBUFSIZE];
- size_t len = 0;
+ char * tmpbuf;
+ size_t len;
int i;
- /* This is all screwed up if we run out of space */
- for (i = 0; i < adomains; i++)
- len += snprintf(tmpbuf + len, TMPBUFSIZE - len,
- "%u ", (unsigned int)active_domains[i]);
- len += snprintf(tmpbuf + len, TMPBUFSIZE - len, "\n");
- return simple_read_from_buffer((void __user *)buf, count,
- offset, tmpbuf, len);
+ ssize_t retval;
+
+ if (!(tmpbuf = kmalloc(TMPBUFSIZE, GFP_KERNEL)))
+ return -ENOMEM;
+
+ mutex_lock(&adom_mutex);
+
+ len = 0;
+ for (i = 0; i < adomains; i++)
+ len += snprintf(tmpbuf + len,
+ len < TMPBUFSIZE ? TMPBUFSIZE - len : 0,
+ "%u ", active_domains[i]);
+ WARN_ON(len > TMPBUFSIZE);
+ if (len != 0 && len <= TMPBUFSIZE)
+ tmpbuf[len-1] = ''\n'';
+
+ mutex_unlock(&adom_mutex);
+
+ retval = simple_read_from_buffer(buf, count, offset, tmpbuf, len);
+
+ kfree(tmpbuf);
+ return retval;
}
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel