Browse Source

[PATCH] oprofile: fix potential deadlock on oprofilefs_lock

nmi_cpu_setup() is called from hardirq context and acquires oprofilefs_lock.
alloc_event_buffer() and oprofilefs_ulong_from_user() acquire this lock
without disabling irqs, which could deadlock.

Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Jiri Kosina 18 years ago
parent
commit
4dfc896e90
2 changed files with 6 additions and 4 deletions
  1. 3 2
      drivers/oprofile/event_buffer.c
  2. 3 2
      drivers/oprofile/oprofilefs.c

+ 3 - 2
drivers/oprofile/event_buffer.c

@@ -70,11 +70,12 @@ void wake_up_buffer_waiter(void)
 int alloc_event_buffer(void)
 int alloc_event_buffer(void)
 {
 {
 	int err = -ENOMEM;
 	int err = -ENOMEM;
+	unsigned long flags;
 
 
-	spin_lock(&oprofilefs_lock);
+	spin_lock_irqsave(&oprofilefs_lock, flags);
 	buffer_size = fs_buffer_size;
 	buffer_size = fs_buffer_size;
 	buffer_watershed = fs_buffer_watershed;
 	buffer_watershed = fs_buffer_watershed;
-	spin_unlock(&oprofilefs_lock);
+	spin_unlock_irqrestore(&oprofilefs_lock, flags);
  
  
 	if (buffer_watershed >= buffer_size)
 	if (buffer_watershed >= buffer_size)
 		return -EINVAL;
 		return -EINVAL;

+ 3 - 2
drivers/oprofile/oprofilefs.c

@@ -65,6 +65,7 @@ ssize_t oprofilefs_ulong_to_user(unsigned long val, char __user * buf, size_t co
 int oprofilefs_ulong_from_user(unsigned long * val, char const __user * buf, size_t count)
 int oprofilefs_ulong_from_user(unsigned long * val, char const __user * buf, size_t count)
 {
 {
 	char tmpbuf[TMPBUFSIZE];
 	char tmpbuf[TMPBUFSIZE];
+	unsigned long flags;
 
 
 	if (!count)
 	if (!count)
 		return 0;
 		return 0;
@@ -77,9 +78,9 @@ int oprofilefs_ulong_from_user(unsigned long * val, char const __user * buf, siz
 	if (copy_from_user(tmpbuf, buf, count))
 	if (copy_from_user(tmpbuf, buf, count))
 		return -EFAULT;
 		return -EFAULT;
 
 
-	spin_lock(&oprofilefs_lock);
+	spin_lock_irqsave(&oprofilefs_lock, flags);
 	*val = simple_strtoul(tmpbuf, NULL, 0);
 	*val = simple_strtoul(tmpbuf, NULL, 0);
-	spin_unlock(&oprofilefs_lock);
+	spin_unlock_irqrestore(&oprofilefs_lock, flags);
 	return 0;
 	return 0;
 }
 }