Commit d37fcff5 authored by Hirokazu Takata's avatar Hirokazu Takata Committed by Linus Torvalds

[PATCH] m32r: fix sys_tas system call for m32r

This patch fixes a sys_tas system call for m32r.

- This patch fixes an Oops at sys_tas() in case CONFIG_SMP && CONFIG_PREEMPT.
  > Unable to handle kernel paging request at virtual address XXXXXXXX

  It is because a page fault happens at the spin_locked region in sys_tas()
  and in_atomic() checks preempt_count, but spin_lock() already counts up
  the preemt_count.

  arch/m32r/kernel/sys_m32r.c:
    32  /*
    33   * sys_tas() - test-and-set
    34   * linuxthreads testing version
    35   */
    36  #ifndef CONFIG_SMP
    37  asmlinkage int sys_tas(int *addr)
    38  {
    39          int oldval;
    40          unsigned long flags;
    41
    42          if (!access_ok(VERIFY_WRITE, addr, sizeof (int)))
    43                  return -EFAULT;
    44          local_irq_save(flags);
    45          oldval = *addr;
    46          *addr = 1;
    47          local_irq_restore(flags);
    48          return oldval;
    49  }
    50  #else /* CONFIG_SMP */
    51  #include <linux/spinlock.h>
    52
    53  static spinlock_t tas_lock = SPIN_LOCK_UNLOCKED;
    54
    55  asmlinkage int sys_tas(int *addr)
    56  {
    57          int oldval;
    58
    59          if (!access_ok(VERIFY_WRITE, addr, sizeof (int)))
    60                  return -EFAULT;
    61
    62          spin_lock(&tas_lock);
    63          oldval = *addr;

	/* <<< ATTENTION >>>
	 * A page fault may happen here, because "addr" points an
	 * user-space area.
	 */

    64          *addr = 1;
    65          spin_unlock(&tas_lock);
    66
    67          return oldval;
    68  }
    69  #endif /* CONFIG_SMP */

  arch/mm/fault.c:
   137  /*
   138   * If we're in an interrupt or have no user context or are runni
ng in an
   139   * atomic region then we must not take the fault..
   140   */
   141  if (in_atomic() || !mm)
   142          goto bad_area_nosemaphore;

- sys_tas() is used for user-level mutual exclusion for the m32r,
  which is prepared to implement a linuxthreads library.
  The above problem may be happened in a program, which uses
  pthread_mutex_lock(), calls sys_tas().

  The current m32r instruction set has no user-level locking
  functions for mutual exclusion.
  # I hope it will be fixed in the future...

- This patch fixes the problem by using _raw_spin_lock() instead of
  spin_lock().  spin_lock() increments up preemt_count, on the contrary,
  _raw_sping_lock() does not.

  # I think this fix is just a temporary work around, and
  # it is preferable to be rewrite to make it simpler by using 
  # asm() function or something...

	* arch/m32r/kernel/sys_m32r.c:
	- Fix sys_tas() for CONFIG_SMP && CONFIG_PREEMPT.
Signed-off-by: default avatarHayato Fujiwara <fujiwara@linux-m32r.org>
Signed-off-by: default avatarHirokazu Takata <takata@linux-m32r.org>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 0b43f270
...@@ -57,10 +57,10 @@ asmlinkage int sys_tas(int *addr) ...@@ -57,10 +57,10 @@ asmlinkage int sys_tas(int *addr)
if (!access_ok(VERIFY_WRITE, addr, sizeof (int))) if (!access_ok(VERIFY_WRITE, addr, sizeof (int)))
return -EFAULT; return -EFAULT;
spin_lock(&tas_lock); _raw_spin_lock(&tas_lock);
oldval = *addr; oldval = *addr;
*addr = 1; *addr = 1;
spin_unlock(&tas_lock); _raw_spin_unlock(&tas_lock);
return oldval; return oldval;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment