• Hirokazu Takata's avatar
    [PATCH] m32r: fix sys_tas system call for m32r · d37fcff5
    Hirokazu Takata authored
    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>
    d37fcff5
sys_m32r.c 4.67 KB