]> Pileus Git - ~andy/linux/blobdiff - ipc/sem.c
Merge branch 'kbuild' of git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild
[~andy/linux] / ipc / sem.c
index 5cf7b4c093b3092b6038437f4546f836173f3611..899b598b63be30bb70f1182edb2b9b91a5e50bd9 100644 (file)
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -269,6 +269,8 @@ static inline void sem_unlock(struct sem_array *sma, int locknum)
 /*
  * sem_lock_(check_) routines are called in the paths where the rw_mutex
  * is not held.
+ *
+ * The caller holds the RCU read lock.
  */
 static inline struct sem_array *sem_obtain_lock(struct ipc_namespace *ns,
                        int id, struct sembuf *sops, int nsops, int *locknum)
@@ -276,12 +278,9 @@ static inline struct sem_array *sem_obtain_lock(struct ipc_namespace *ns,
        struct kern_ipc_perm *ipcp;
        struct sem_array *sma;
 
-       rcu_read_lock();
        ipcp = ipc_obtain_object(&sem_ids(ns), id);
-       if (IS_ERR(ipcp)) {
-               sma = ERR_CAST(ipcp);
-               goto err;
-       }
+       if (IS_ERR(ipcp))
+               return ERR_CAST(ipcp);
 
        sma = container_of(ipcp, struct sem_array, sem_perm);
        *locknum = sem_lock(sma, sops, nsops);
@@ -293,10 +292,7 @@ static inline struct sem_array *sem_obtain_lock(struct ipc_namespace *ns,
                return container_of(ipcp, struct sem_array, sem_perm);
 
        sem_unlock(sma, *locknum);
-       sma = ERR_PTR(-EINVAL);
-err:
-       rcu_read_unlock();
-       return sma;
+       return ERR_PTR(-EINVAL);
 }
 
 static inline struct sem_array *sem_obtain_object(struct ipc_namespace *ns, int id)
@@ -322,7 +318,6 @@ static inline struct sem_array *sem_obtain_object_check(struct ipc_namespace *ns
 
 static inline void sem_lock_and_putref(struct sem_array *sma)
 {
-       rcu_read_lock();
        sem_lock(sma, NULL, -1);
        ipc_rcu_putref(sma);
 }
@@ -953,8 +948,8 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid,
 
                memset(&tbuf, 0, sizeof(tbuf));
 
+               rcu_read_lock();
                if (cmd == SEM_STAT) {
-                       rcu_read_lock();
                        sma = sem_obtain_object(ns, semid);
                        if (IS_ERR(sma)) {
                                err = PTR_ERR(sma);
@@ -962,7 +957,6 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid,
                        }
                        id = sma->sem_perm.id;
                } else {
-                       rcu_read_lock();
                        sma = sem_obtain_object_check(ns, semid);
                        if (IS_ERR(sma)) {
                                err = PTR_ERR(sma);
@@ -1082,17 +1076,12 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
        nsems = sma->sem_nsems;
 
        err = -EACCES;
-       if (ipcperms(ns, &sma->sem_perm,
-                       cmd == SETALL ? S_IWUGO : S_IRUGO)) {
-               rcu_read_unlock();
-               goto out_wakeup;
-       }
+       if (ipcperms(ns, &sma->sem_perm, cmd == SETALL ? S_IWUGO : S_IRUGO))
+               goto out_rcu_wakeup;
 
        err = security_sem_semctl(sma, cmd);
-       if (err) {
-               rcu_read_unlock();
-               goto out_wakeup;
-       }
+       if (err)
+               goto out_rcu_wakeup;
 
        err = -EACCES;
        switch (cmd) {
@@ -1117,6 +1106,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
                                return -ENOMEM;
                        }
 
+                       rcu_read_lock();
                        sem_lock_and_putref(sma);
                        if (sma->sem_perm.deleted) {
                                sem_unlock(sma, -1);
@@ -1166,6 +1156,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
                                goto out_free;
                        }
                }
+               rcu_read_lock();
                sem_lock_and_putref(sma);
                if (sma->sem_perm.deleted) {
                        sem_unlock(sma, -1);
@@ -1191,10 +1182,8 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
        /* GETVAL, GETPID, GETNCTN, GETZCNT: fall-through */
        }
        err = -EINVAL;
-       if (semnum < 0 || semnum >= nsems) {
-               rcu_read_unlock();
-               goto out_wakeup;
-       }
+       if (semnum < 0 || semnum >= nsems)
+               goto out_rcu_wakeup;
 
        sem_lock(sma, NULL, -1);
        curr = &sma->sem_base[semnum];
@@ -1216,8 +1205,8 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
 
 out_unlock:
        sem_unlock(sma, -1);
+out_rcu_wakeup:
        rcu_read_unlock();
-out_wakeup:
        wake_up_sem_queue_do(&tasks);
 out_free:
        if(sem_io != fast_sem_io)
@@ -1279,7 +1268,7 @@ static int semctl_down(struct ipc_namespace *ns, int semid,
        err = security_sem_semctl(sma, cmd);
        if (err) {
                rcu_read_unlock();
-               goto out_unlock;
+               goto out_up;
        }
 
        switch(cmd){
@@ -1451,7 +1440,7 @@ static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid)
        }
 
        /* step 3: Acquire the lock on semaphore array */
-       /* This also does the rcu_read_lock() */
+       rcu_read_lock();
        sem_lock_and_putref(sma);
        if (sma->sem_perm.deleted) {
                sem_unlock(sma, -1);
@@ -1588,22 +1577,16 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
        }
 
        error = -EFBIG;
-       if (max >= sma->sem_nsems) {
-               rcu_read_unlock();
-               goto out_wakeup;
-       }
+       if (max >= sma->sem_nsems)
+               goto out_rcu_wakeup;
 
        error = -EACCES;
-       if (ipcperms(ns, &sma->sem_perm, alter ? S_IWUGO : S_IRUGO)) {
-               rcu_read_unlock();
-               goto out_wakeup;
-       }
+       if (ipcperms(ns, &sma->sem_perm, alter ? S_IWUGO : S_IRUGO))
+               goto out_rcu_wakeup;
 
        error = security_sem_semop(sma, sops, nsops, alter);
-       if (error) {
-               rcu_read_unlock();
-               goto out_wakeup;
-       }
+       if (error)
+               goto out_rcu_wakeup;
 
        /*
         * semid identifiers are not unique - find_alloc_undo may have
@@ -1679,6 +1662,7 @@ sleep_again:
                goto out_free;
        }
 
+       rcu_read_lock();
        sma = sem_obtain_lock(ns, semid, sops, nsops, &locknum);
 
        /*
@@ -1690,6 +1674,7 @@ sleep_again:
         * Array removed? If yes, leave without sem_unlock().
         */
        if (IS_ERR(sma)) {
+               rcu_read_unlock();
                goto out_free;
        }
 
@@ -1719,8 +1704,8 @@ sleep_again:
 
 out_unlock_free:
        sem_unlock(sma, locknum);
+out_rcu_wakeup:
        rcu_read_unlock();
-out_wakeup:
        wake_up_sem_queue_do(&tasks);
 out_free:
        if(sops != fast_sops)