Skip to content

Commit

Permalink
ARC: change return value of userspace cmpxchg assist syscall
Browse files Browse the repository at this point in the history
The original syscall only used to return errno to indicate if cmpxchg
succeeded. It was not returning the "previous" value which typical cmpxchg
callers are interested in to build their slowpaths or retry loops.
Given user preemption in syscall return path etc, it is not wise to
check this in userspace afterwards, but should be what kernel actually
observed in the syscall.

So change the syscall interface to always return the previous value and
additionally set Z flag to indicate whether operation succeeded or not
(just like ARM implementation when they used to have this syscall)
The flag approach avoids having to put_user errno which is nice given
the use case for this syscall cares mostly about the "previous" value.

Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
  • Loading branch information
Vineet Gupta committed Nov 7, 2016
1 parent a79a812 commit e6e335b
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 9 deletions.
2 changes: 2 additions & 0 deletions arch/arc/include/asm/arcregs.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,14 @@
#define STATUS_AE_BIT 5 /* Exception active */
#define STATUS_DE_BIT 6 /* PC is in delay slot */
#define STATUS_U_BIT 7 /* User/Kernel mode */
#define STATUS_Z_BIT 11
#define STATUS_L_BIT 12 /* Loop inhibit */

/* These masks correspond to the status word(STATUS_32) bits */
#define STATUS_AE_MASK (1<<STATUS_AE_BIT)
#define STATUS_DE_MASK (1<<STATUS_DE_BIT)
#define STATUS_U_MASK (1<<STATUS_U_BIT)
#define STATUS_Z_MASK (1<<STATUS_Z_BIT)
#define STATUS_L_MASK (1<<STATUS_L_BIT)

/*
Expand Down
20 changes: 11 additions & 9 deletions arch/arc/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ SYSCALL_DEFINE0(arc_gettls)

SYSCALL_DEFINE3(arc_usr_cmpxchg, int *, uaddr, int, expected, int, new)
{
int uval;
int ret;
struct pt_regs *regs = current_pt_regs();
int uval = -EFAULT;

/*
* This is only for old cores lacking LLOCK/SCOND, which by defintion
Expand All @@ -54,24 +54,26 @@ SYSCALL_DEFINE3(arc_usr_cmpxchg, int *, uaddr, int, expected, int, new)
*/
WARN_ON_ONCE(IS_ENABLED(CONFIG_SMP));

/* Z indicates to userspace if operation succeded */
regs->status32 &= ~STATUS_Z_MASK;

if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
return -EFAULT;

preempt_disable();

ret = __get_user(uval, uaddr);
if (ret)
if (__get_user(uval, uaddr))
goto done;

if (uval != expected)
ret = -EAGAIN;
else
ret = __put_user(new, uaddr);
if (uval == expected) {
if (!__put_user(new, uaddr))
regs->status32 |= STATUS_Z_MASK;
}

done:
preempt_enable();

return ret;
return uval;
}

void arch_cpu_idle(void)
Expand Down

0 comments on commit e6e335b

Please sign in to comment.