struct sem *sem = sma->sem_base + locknum;
spin_unlock(&sem->lock);
}
- rcu_read_unlock();
}
/*
* 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)
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);
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)
static inline void sem_lock_and_putref(struct sem_array *sma)
{
- rcu_read_lock();
sem_lock(sma, NULL, -1);
ipc_rcu_putref(sma);
}
-static inline void sem_getref_and_unlock(struct sem_array *sma)
-{
- WARN_ON_ONCE(!ipc_rcu_getref(sma));
- sem_unlock(sma, -1);
-}
-
static inline void sem_putref(struct sem_array *sma)
{
- sem_lock_and_putref(sma);
- sem_unlock(sma, -1);
-}
-
-/*
- * Call inside the rcu read section.
- */
-static inline void sem_getref(struct sem_array *sma)
-{
- sem_lock(sma, NULL, -1);
- WARN_ON_ONCE(!ipc_rcu_getref(sma));
- sem_unlock(sma, -1);
+ ipc_rcu_putref(sma);
}
static inline void sem_rmid(struct ipc_namespace *ns, struct sem_array *s)
sma->sem_nsems = nsems;
sma->sem_ctime = get_seconds();
sem_unlock(sma, -1);
+ rcu_read_unlock();
return sma->sem_perm.id;
}
struct sem_queue * q;
semncnt = 0;
+ list_for_each_entry(q, &sma->sem_base[semnum].sem_pending, list) {
+ struct sembuf * sops = q->sops;
+ BUG_ON(sops->sem_num != semnum);
+ if ((sops->sem_op < 0) && !(sops->sem_flg & IPC_NOWAIT))
+ semncnt++;
+ }
+
list_for_each_entry(q, &sma->sem_pending, list) {
struct sembuf * sops = q->sops;
int nsops = q->nsops;
struct sem_queue * q;
semzcnt = 0;
+ list_for_each_entry(q, &sma->sem_base[semnum].sem_pending, list) {
+ struct sembuf * sops = q->sops;
+ BUG_ON(sops->sem_num != semnum);
+ if ((sops->sem_op == 0) && !(sops->sem_flg & IPC_NOWAIT))
+ semzcnt++;
+ }
+
list_for_each_entry(q, &sma->sem_pending, list) {
struct sembuf * sops = q->sops;
int nsops = q->nsops;
/* Remove the semaphore set from the IDR */
sem_rmid(ns, sma);
sem_unlock(sma, -1);
+ rcu_read_unlock();
wake_up_sem_queue_do(&tasks);
ns->used_sems -= sma->sem_nsems;
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);
}
id = sma->sem_perm.id;
} else {
- rcu_read_lock();
sma = sem_obtain_object_check(ns, semid);
if (IS_ERR(sma)) {
err = PTR_ERR(sma);
/* maybe some queued-up processes were waiting for this */
do_smart_update(sma, NULL, 0, 0, &tasks);
sem_unlock(sma, -1);
+ rcu_read_unlock();
wake_up_sem_queue_do(&tasks);
return 0;
}
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) {
ushort __user *array = p;
int i;
+ sem_lock(sma, NULL, -1);
if(nsems > SEMMSL_FAST) {
- sem_getref(sma);
-
+ if (!ipc_rcu_getref(sma)) {
+ sem_unlock(sma, -1);
+ rcu_read_unlock();
+ err = -EIDRM;
+ goto out_free;
+ }
+ sem_unlock(sma, -1);
+ rcu_read_unlock();
sem_io = ipc_alloc(sizeof(ushort)*nsems);
if(sem_io == NULL) {
sem_putref(sma);
return -ENOMEM;
}
+ rcu_read_lock();
sem_lock_and_putref(sma);
if (sma->sem_perm.deleted) {
sem_unlock(sma, -1);
+ rcu_read_unlock();
err = -EIDRM;
goto out_free;
}
- } else
- sem_lock(sma, NULL, -1);
-
+ }
for (i = 0; i < sma->sem_nsems; i++)
sem_io[i] = sma->sem_base[i].semval;
sem_unlock(sma, -1);
+ rcu_read_unlock();
err = 0;
if(copy_to_user(array, sem_io, nsems*sizeof(ushort)))
err = -EFAULT;
goto out_free;
}
}
+ rcu_read_lock();
sem_lock_and_putref(sma);
if (sma->sem_perm.deleted) {
sem_unlock(sma, -1);
+ rcu_read_unlock();
err = -EIDRM;
goto out_free;
}
/* 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];
out_unlock:
sem_unlock(sma, -1);
-out_wakeup:
+out_rcu_wakeup:
+ rcu_read_unlock();
wake_up_sem_queue_do(&tasks);
out_free:
if(sem_io != fast_sem_io)
err = security_sem_semctl(sma, cmd);
if (err) {
rcu_read_unlock();
- goto out_unlock;
+ goto out_up;
}
switch(cmd){
out_unlock:
sem_unlock(sma, -1);
+ rcu_read_unlock();
out_up:
up_write(&sem_ids(ns).rw_mutex);
return err;
}
/* step 3: Acquire the lock on semaphore array */
+ rcu_read_lock();
sem_lock_and_putref(sma);
if (sma->sem_perm.deleted) {
sem_unlock(sma, -1);
+ rcu_read_unlock();
kfree(new);
un = ERR_PTR(-EIDRM);
goto out;
success:
spin_unlock(&ulp->lock);
- rcu_read_lock();
sem_unlock(sma, -1);
out:
return un;
}
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
sleep_again:
current->state = TASK_INTERRUPTIBLE;
sem_unlock(sma, locknum);
+ rcu_read_unlock();
if (timeout)
jiffies_left = schedule_timeout(jiffies_left);
goto out_free;
}
+ rcu_read_lock();
sma = sem_obtain_lock(ns, semid, sops, nsops, &locknum);
/*
* Array removed? If yes, leave without sem_unlock().
*/
if (IS_ERR(sma)) {
+ rcu_read_unlock();
goto out_free;
}
out_unlock_free:
sem_unlock(sma, locknum);
-out_wakeup:
+out_rcu_wakeup:
+ rcu_read_unlock();
wake_up_sem_queue_do(&tasks);
out_free:
if(sops != fast_sops)
* exactly the same semid. Nothing to do.
*/
sem_unlock(sma, -1);
+ rcu_read_unlock();
continue;
}
INIT_LIST_HEAD(&tasks);
do_smart_update(sma, NULL, 0, 1, &tasks);
sem_unlock(sma, -1);
+ rcu_read_unlock();
wake_up_sem_queue_do(&tasks);
kfree_rcu(un, rcu);