* [PATCH 0/3] xenoprof fixes
@ 2006-05-15 16:31 Markus Armbruster
2006-05-15 16:31 ` [PATCH 1/3] xenoprof fixes: sleep with interrupts disabled Markus Armbruster
` (3 more replies)
0 siblings, 4 replies; 21+ messages in thread
From: Markus Armbruster @ 2006-05-15 16:31 UTC (permalink / raw)
To: xen-devel
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.
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH 1/3] xenoprof fixes: sleep with interrupts disabled
2006-05-15 16:31 [PATCH 0/3] xenoprof fixes Markus Armbruster
@ 2006-05-15 16:31 ` Markus Armbruster
2006-05-15 17:33 ` Markus Armbruster
2006-05-15 16:32 ` [PATCH 2/3] xenoprof fixes: active_domains races Markus Armbruster
` (2 subsequent siblings)
3 siblings, 1 reply; 21+ messages in thread
From: Markus Armbruster @ 2006-05-15 16:31 UTC (permalink / raw)
To: xen-devel
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;
}
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH 2/3] xenoprof fixes: active_domains races
2006-05-15 16:31 [PATCH 0/3] xenoprof fixes Markus Armbruster
2006-05-15 16:31 ` [PATCH 1/3] xenoprof fixes: sleep with interrupts disabled Markus Armbruster
@ 2006-05-15 16:32 ` Markus Armbruster
2006-05-15 17:34 ` Markus Armbruster
2006-05-15 18:53 ` [PATCH 2/3] xenoprof fixes: active_domains races Chris Wright
2006-05-15 16:33 ` [PATCH 3/3] xenoprof fixes: active_domains cleanup Markus Armbruster
2006-05-15 16:55 ` [PATCH 0/3] xenoprof fixes Keir Fraser
3 siblings, 2 replies; 21+ messages in thread
From: Markus Armbruster @ 2006-05-15 16:32 UTC (permalink / raw)
To: xen-devel
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);
}
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH 3/3] xenoprof fixes: active_domains cleanup
2006-05-15 16:31 [PATCH 0/3] xenoprof fixes Markus Armbruster
2006-05-15 16:31 ` [PATCH 1/3] xenoprof fixes: sleep with interrupts disabled Markus Armbruster
2006-05-15 16:32 ` [PATCH 2/3] xenoprof fixes: active_domains races Markus Armbruster
@ 2006-05-15 16:33 ` Markus Armbruster
2006-05-15 17:34 ` Markus Armbruster
2006-05-15 16:55 ` [PATCH 0/3] xenoprof fixes Keir Fraser
3 siblings, 1 reply; 21+ messages in thread
From: Markus Armbruster @ 2006-05-15 16:33 UTC (permalink / raw)
To: xen-devel
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;
}
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH 0/3] xenoprof fixes
2006-05-15 16:31 [PATCH 0/3] xenoprof fixes Markus Armbruster
` (2 preceding siblings ...)
2006-05-15 16:33 ` [PATCH 3/3] xenoprof fixes: active_domains cleanup Markus Armbruster
@ 2006-05-15 16:55 ` Keir Fraser
2006-05-15 17:14 ` Markus Armbruster
3 siblings, 1 reply; 21+ messages in thread
From: Keir Fraser @ 2006-05-15 16:55 UTC (permalink / raw)
To: Markus Armbruster; +Cc: 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
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH 0/3] xenoprof fixes
2006-05-15 16:55 ` [PATCH 0/3] xenoprof fixes Keir Fraser
@ 2006-05-15 17:14 ` Markus Armbruster
2006-05-15 17:19 ` Keir Fraser
0 siblings, 1 reply; 21+ messages in thread
From: Markus Armbruster @ 2006-05-15 17:14 UTC (permalink / raw)
To: 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>
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH 0/3] xenoprof fixes
2006-05-15 17:14 ` Markus Armbruster
@ 2006-05-15 17:19 ` Keir Fraser
0 siblings, 0 replies; 21+ messages in thread
From: Keir Fraser @ 2006-05-15 17:19 UTC (permalink / raw)
To: Markus Armbruster; +Cc: 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
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH 1/3] xenoprof fixes: sleep with interrupts disabled
2006-05-15 16:31 ` [PATCH 1/3] xenoprof fixes: sleep with interrupts disabled Markus Armbruster
@ 2006-05-15 17:33 ` Markus Armbruster
2006-05-16 8:06 ` Keir Fraser
0 siblings, 1 reply; 21+ messages in thread
From: Markus Armbruster @ 2006-05-15 17:33 UTC (permalink / raw)
To: xen-devel
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;
}
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH 2/3] xenoprof fixes: active_domains races
2006-05-15 16:32 ` [PATCH 2/3] xenoprof fixes: active_domains races Markus Armbruster
@ 2006-05-15 17:34 ` Markus Armbruster
2006-05-16 8:09 ` Keir Fraser
2006-05-15 18:53 ` [PATCH 2/3] xenoprof fixes: active_domains races Chris Wright
1 sibling, 1 reply; 21+ messages in thread
From: Markus Armbruster @ 2006-05-15 17:34 UTC (permalink / raw)
To: xen-devel
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);
}
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH 3/3] xenoprof fixes: active_domains cleanup
2006-05-15 16:33 ` [PATCH 3/3] xenoprof fixes: active_domains cleanup Markus Armbruster
@ 2006-05-15 17:34 ` Markus Armbruster
0 siblings, 0 replies; 21+ messages in thread
From: Markus Armbruster @ 2006-05-15 17:34 UTC (permalink / raw)
To: xen-devel
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;
}
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH 2/3] xenoprof fixes: active_domains races
2006-05-15 16:32 ` [PATCH 2/3] xenoprof fixes: active_domains races Markus Armbruster
2006-05-15 17:34 ` Markus Armbruster
@ 2006-05-15 18:53 ` Chris Wright
2006-05-15 19:15 ` Markus Armbruster
1 sibling, 1 reply; 21+ messages in thread
From: Chris Wright @ 2006-05-15 18:53 UTC (permalink / raw)
To: Markus Armbruster; +Cc: xen-devel
* 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
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH 2/3] xenoprof fixes: active_domains races
2006-05-15 18:53 ` [PATCH 2/3] xenoprof fixes: active_domains races Chris Wright
@ 2006-05-15 19:15 ` Markus Armbruster
2006-05-15 21:51 ` Santos, Jose Renato G
0 siblings, 1 reply; 21+ messages in thread
From: Markus Armbruster @ 2006-05-15 19:15 UTC (permalink / raw)
To: xen-devel
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,
> -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?
^ permalink raw reply [flat|nested] 21+ messages in thread
* RE: [PATCH 2/3] xenoprof fixes: active_domains races
2006-05-15 19:15 ` Markus Armbruster
@ 2006-05-15 21:51 ` Santos, Jose Renato G
2006-05-16 7:23 ` Chris Wright
2006-05-16 7:40 ` Keir Fraser
0 siblings, 2 replies; 21+ messages in thread
From: Santos, Jose Renato G @ 2006-05-15 21:51 UTC (permalink / raw)
To: Markus Armbruster, xen-devel
>> > 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
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH 2/3] xenoprof fixes: active_domains races
2006-05-15 21:51 ` Santos, Jose Renato G
@ 2006-05-16 7:23 ` Chris Wright
2006-05-16 7:40 ` Keir Fraser
1 sibling, 0 replies; 21+ messages in thread
From: Chris Wright @ 2006-05-16 7:23 UTC (permalink / raw)
To: Santos, Jose Renato G; +Cc: xen-devel, Markus Armbruster
* 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
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH 2/3] xenoprof fixes: active_domains races
2006-05-15 21:51 ` Santos, Jose Renato G
2006-05-16 7:23 ` Chris Wright
@ 2006-05-16 7:40 ` Keir Fraser
1 sibling, 0 replies; 21+ messages in thread
From: Keir Fraser @ 2006-05-16 7:40 UTC (permalink / raw)
To: Santos, Jose Renato G; +Cc: xen-devel, Markus Armbruster
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
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: Re: [PATCH 1/3] xenoprof fixes: sleep with interrupts disabled
2006-05-15 17:33 ` Markus Armbruster
@ 2006-05-16 8:06 ` Keir Fraser
0 siblings, 0 replies; 21+ messages in thread
From: Keir Fraser @ 2006-05-16 8:06 UTC (permalink / raw)
To: Markus Armbruster; +Cc: xen-devel
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
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: Re: [PATCH 2/3] xenoprof fixes: active_domains races
2006-05-15 17:34 ` Markus Armbruster
@ 2006-05-16 8:09 ` Keir Fraser
2006-05-16 9:47 ` Markus Armbruster
0 siblings, 1 reply; 21+ messages in thread
From: Keir Fraser @ 2006-05-16 8:09 UTC (permalink / raw)
To: Markus Armbruster; +Cc: xen-devel
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
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: Re: [PATCH 2/3] xenoprof fixes: active_domains races
2006-05-16 8:09 ` Keir Fraser
@ 2006-05-16 9:47 ` Markus Armbruster
2006-05-16 9:48 ` Keir Fraser
0 siblings, 1 reply; 21+ messages in thread
From: Markus Armbruster @ 2006-05-16 9:47 UTC (permalink / raw)
To: Keir Fraser; +Cc: xen-devel
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.
>
> -- Keir
Is 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?
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: Re: [PATCH 2/3] xenoprof fixes: active_domains races
2006-05-16 9:47 ` Markus Armbruster
@ 2006-05-16 9:48 ` Keir Fraser
2006-05-16 11:47 ` Markus Armbruster
2006-05-16 11:48 ` [PATCH] xenoprof fixes: active_domains races & cleanup Markus Armbruster
0 siblings, 2 replies; 21+ messages in thread
From: Keir Fraser @ 2006-05-16 9:48 UTC (permalink / raw)
To: Markus Armbruster; +Cc: xen-devel
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
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: Re: [PATCH 2/3] xenoprof fixes: active_domains races
2006-05-16 9:48 ` Keir Fraser
@ 2006-05-16 11:47 ` Markus Armbruster
2006-05-16 11:48 ` [PATCH] xenoprof fixes: active_domains races & cleanup Markus Armbruster
1 sibling, 0 replies; 21+ messages in thread
From: Markus Armbruster @ 2006-05-16 11:47 UTC (permalink / raw)
To: Keir Fraser; +Cc: xen-devel
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!
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH] xenoprof fixes: active_domains races & cleanup
2006-05-16 9:48 ` Keir Fraser
2006-05-16 11:47 ` Markus Armbruster
@ 2006-05-16 11:48 ` Markus Armbruster
1 sibling, 0 replies; 21+ messages in thread
From: Markus Armbruster @ 2006-05-16 11:48 UTC (permalink / raw)
To: Keir Fraser; +Cc: xen-devel
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;
}
^ permalink raw reply [flat|nested] 21+ messages in thread
end of thread, other threads:[~2006-05-16 11:48 UTC | newest]
Thread overview: 21+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-05-15 16:31 [PATCH 0/3] xenoprof fixes Markus Armbruster
2006-05-15 16:31 ` [PATCH 1/3] xenoprof fixes: sleep with interrupts disabled Markus Armbruster
2006-05-15 17:33 ` Markus Armbruster
2006-05-16 8:06 ` Keir Fraser
2006-05-15 16:32 ` [PATCH 2/3] xenoprof fixes: active_domains races Markus Armbruster
2006-05-15 17:34 ` Markus Armbruster
2006-05-16 8:09 ` Keir Fraser
2006-05-16 9:47 ` Markus Armbruster
2006-05-16 9:48 ` Keir Fraser
2006-05-16 11:47 ` Markus Armbruster
2006-05-16 11:48 ` [PATCH] xenoprof fixes: active_domains races & cleanup Markus Armbruster
2006-05-15 18:53 ` [PATCH 2/3] xenoprof fixes: active_domains races Chris Wright
2006-05-15 19:15 ` Markus Armbruster
2006-05-15 21:51 ` Santos, Jose Renato G
2006-05-16 7:23 ` Chris Wright
2006-05-16 7:40 ` Keir Fraser
2006-05-15 16:33 ` [PATCH 3/3] xenoprof fixes: active_domains cleanup Markus Armbruster
2006-05-15 17:34 ` Markus Armbruster
2006-05-15 16:55 ` [PATCH 0/3] xenoprof fixes Keir Fraser
2006-05-15 17:14 ` Markus Armbruster
2006-05-15 17:19 ` Keir Fraser
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.