Messages in this thread Patch in this message | | | Date | Tue, 26 Mar 2013 16:00:59 -0400 | From | Rik van Riel <> | Subject | [PATCH -mm -next] ipc,sem: untangle RCU locking with find_alloc_undo |
| |
On Tue, 26 Mar 2013 14:07:14 -0400 Sasha Levin <sasha.levin@oracle.com> wrote:
> > Not necessarily, we do release everything at the end of the function: > > out_unlock_free: > > sem_unlock(sma, locknum); > > Ow, there's a rcu_read_unlock() in sem_unlock()? This complicates things even > more I suspect. If un is non-NULL we'll be unlocking rcu lock twice?
Sasha, this patch should resolve the RCU tangle, by making sure we only ever take the rcu_read_lock once in semtimedop.
---8<---
The ipc semaphore code has a nasty RCU locking tangle, with both find_alloc_undo and semtimedop taking the rcu_read_lock(). The code can be cleaned up somewhat by only taking the rcu_read_lock once.
There are no other callers to find_alloc_undo.
This should also solve the trinity issue reported by Sasha Levin.
Reported-by: Sasha Levin <sasha.levin@oracle.com> Signed-off-by: Rik van Riel <riel@redhat.com> --- ipc/sem.c | 31 +++++++++---------------------- 1 files changed, 9 insertions(+), 22 deletions(-)
diff --git a/ipc/sem.c b/ipc/sem.c index f46441a..2ec2945 100644 --- a/ipc/sem.c +++ b/ipc/sem.c @@ -1646,22 +1646,23 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops, alter = 1; } + INIT_LIST_HEAD(&tasks); + if (undos) { + /* On success, find_alloc_undo takes the rcu_read_lock */ un = find_alloc_undo(ns, semid); if (IS_ERR(un)) { error = PTR_ERR(un); goto out_free; } - } else + } else { un = NULL; + rcu_read_lock(); + } - INIT_LIST_HEAD(&tasks); - - rcu_read_lock(); sma = sem_obtain_object_check(ns, semid); if (IS_ERR(sma)) { - if (un) - rcu_read_unlock(); + rcu_read_unlock(); error = PTR_ERR(sma); goto out_free; } @@ -1693,22 +1694,8 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops, */ error = -EIDRM; locknum = sem_lock(sma, sops, nsops); - if (un) { - if (un->semid == -1) { - rcu_read_unlock(); - goto out_unlock_free; - } else { - /* - * rcu lock can be released, "un" cannot disappear: - * - sem_lock is acquired, thus IPC_RMID is - * impossible. - * - exit_sem is impossible, it always operates on - * current (or a dead task). - */ - - rcu_read_unlock(); - } - } + if (un && un->semid == -1) + goto out_unlock_free; error = try_atomic_semop (sma, sops, nsops, un, task_tgid_vnr(current)); if (error <= 0) {
| |