lkml.org 
[lkml]   [2013]   [Jan]   [22]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
Subject[RFC PATCH 3/6] ipc: convert ipc objects to use queue spinlock API
Date
This change converts the IPC message queues, semaphores and shm segments
to use the queue spinlock API.

This is relatively large, but mostly mechanical, mostly adding
struct q_spinlock_node variables before locking ipc objects and passing
them all the way to the actual locking and unlocking functions.

In most cases the struct q_spinlock_node is allocated on stack, but
there are exceptions such as the sysvipc_proc_seqops allocating it
within their iterator structure.

Signed-off-by: Michel Lespinasse <walken@google.com>

---
include/linux/ipc.h | 4 +-
ipc/msg.c | 61 ++++++++++++++++------------
ipc/namespace.c | 8 ++-
ipc/sem.c | 112 ++++++++++++++++++++++++++++----------------------
ipc/shm.c | 95 ++++++++++++++++++++++++-------------------
ipc/util.c | 55 ++++++++++++++----------
ipc/util.h | 25 +++++++----
7 files changed, 207 insertions(+), 153 deletions(-)

diff --git a/include/linux/ipc.h b/include/linux/ipc.h
index 8d861b2651f7..81693a8a5177 100644
--- a/include/linux/ipc.h
+++ b/include/linux/ipc.h
@@ -1,7 +1,7 @@
#ifndef _LINUX_IPC_H
#define _LINUX_IPC_H

-#include <linux/spinlock.h>
+#include <linux/queue_spinlock.h>
#include <linux/uidgid.h>
#include <uapi/linux/ipc.h>

@@ -10,7 +10,7 @@
/* used by in-kernel data structures */
struct kern_ipc_perm
{
- spinlock_t lock;
+ struct q_spinlock lock;
int deleted;
int id;
key_t key;
diff --git a/ipc/msg.c b/ipc/msg.c
index a71af5a65abf..aeb32d539f6e 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -69,9 +69,10 @@ struct msg_sender {

#define msg_ids(ns) ((ns)->ids[IPC_MSG_IDS])

-#define msg_unlock(msq) ipc_unlock(&(msq)->q_perm)
+#define msg_unlock(msq,node) ipc_unlock(&(msq)->q_perm, node)

-static void freeque(struct ipc_namespace *, struct kern_ipc_perm *);
+static void freeque(struct ipc_namespace *, struct kern_ipc_perm *,
+ struct q_spinlock_node *);
static int newque(struct ipc_namespace *, struct ipc_params *);
#ifdef CONFIG_PROC_FS
static int sysvipc_msg_proc_show(struct seq_file *s, void *it);
@@ -144,9 +145,10 @@ void __init msg_init(void)
* msg_lock_(check_) routines are called in the paths where the rw_mutex
* is not held.
*/
-static inline struct msg_queue *msg_lock(struct ipc_namespace *ns, int id)
+static inline struct msg_queue *msg_lock(struct ipc_namespace *ns, int id,
+ struct q_spinlock_node *node)
{
- struct kern_ipc_perm *ipcp = ipc_lock(&msg_ids(ns), id);
+ struct kern_ipc_perm *ipcp = ipc_lock(&msg_ids(ns), id, node);

if (IS_ERR(ipcp))
return (struct msg_queue *)ipcp;
@@ -155,9 +157,10 @@ static inline struct msg_queue *msg_lock(struct ipc_namespace *ns, int id)
}

static inline struct msg_queue *msg_lock_check(struct ipc_namespace *ns,
- int id)
+ int id,
+ struct q_spinlock_node *node)
{
- struct kern_ipc_perm *ipcp = ipc_lock_check(&msg_ids(ns), id);
+ struct kern_ipc_perm *ipcp = ipc_lock_check(&msg_ids(ns), id, node);

if (IS_ERR(ipcp))
return (struct msg_queue *)ipcp;
@@ -183,6 +186,7 @@ static int newque(struct ipc_namespace *ns, struct ipc_params *params)
int id, retval;
key_t key = params->key;
int msgflg = params->flg;
+ struct q_spinlock_node node;

msq = ipc_rcu_alloc(sizeof(*msq));
if (!msq)
@@ -201,7 +205,7 @@ static int newque(struct ipc_namespace *ns, struct ipc_params *params)
/*
* ipc_addid() locks msq
*/
- id = ipc_addid(&msg_ids(ns), &msq->q_perm, ns->msg_ctlmni);
+ id = ipc_addid(&msg_ids(ns), &msq->q_perm, ns->msg_ctlmni, &node);
if (id < 0) {
security_msg_queue_free(msq);
ipc_rcu_putref(msq);
@@ -217,7 +221,7 @@ static int newque(struct ipc_namespace *ns, struct ipc_params *params)
INIT_LIST_HEAD(&msq->q_receivers);
INIT_LIST_HEAD(&msq->q_senders);

- msg_unlock(msq);
+ msg_unlock(msq, &node);

return msq->q_perm.id;
}
@@ -276,7 +280,8 @@ static void expunge_all(struct msg_queue *msq, int res)
* msg_ids.rw_mutex (writer) and the spinlock for this message queue are held
* before freeque() is called. msg_ids.rw_mutex remains locked on exit.
*/
-static void freeque(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
+static void freeque(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp,
+ struct q_spinlock_node *node)
{
struct list_head *tmp;
struct msg_queue *msq = container_of(ipcp, struct msg_queue, q_perm);
@@ -284,7 +289,7 @@ static void freeque(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
expunge_all(msq, -EIDRM);
ss_wakeup(&msq->q_senders, 1);
msg_rmid(ns, msq);
- msg_unlock(msq);
+ msg_unlock(msq, node);

tmp = msq->q_messages.next;
while (tmp != &msq->q_messages) {
@@ -415,6 +420,7 @@ static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,
struct msqid64_ds uninitialized_var(msqid64);
struct msg_queue *msq;
int err;
+ struct q_spinlock_node node;

if (cmd == IPC_SET) {
if (copy_msqid_from_user(&msqid64, buf, version))
@@ -422,7 +428,7 @@ static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,
}

ipcp = ipcctl_pre_down(ns, &msg_ids(ns), msqid, cmd,
- &msqid64.msg_perm, msqid64.msg_qbytes);
+ &msqid64.msg_perm, msqid64.msg_qbytes, &node);
if (IS_ERR(ipcp))
return PTR_ERR(ipcp);

@@ -434,7 +440,7 @@ static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,

switch (cmd) {
case IPC_RMID:
- freeque(ns, ipcp);
+ freeque(ns, ipcp, &node);
goto out_up;
case IPC_SET:
if (msqid64.msg_qbytes > ns->msg_ctlmnb &&
@@ -463,7 +469,7 @@ static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,
err = -EINVAL;
}
out_unlock:
- msg_unlock(msq);
+ msg_unlock(msq, &node);
out_up:
up_write(&msg_ids(ns).rw_mutex);
return err;
@@ -474,6 +480,7 @@ SYSCALL_DEFINE3(msgctl, int, msqid, int, cmd, struct msqid_ds __user *, buf)
struct msg_queue *msq;
int err, version;
struct ipc_namespace *ns;
+ struct q_spinlock_node node;

if (msqid < 0 || cmd < 0)
return -EINVAL;
@@ -531,12 +538,12 @@ SYSCALL_DEFINE3(msgctl, int, msqid, int, cmd, struct msqid_ds __user *, buf)
return -EFAULT;

if (cmd == MSG_STAT) {
- msq = msg_lock(ns, msqid);
+ msq = msg_lock(ns, msqid, &node);
if (IS_ERR(msq))
return PTR_ERR(msq);
success_return = msq->q_perm.id;
} else {
- msq = msg_lock_check(ns, msqid);
+ msq = msg_lock_check(ns, msqid, &node);
if (IS_ERR(msq))
return PTR_ERR(msq);
success_return = 0;
@@ -560,7 +567,7 @@ SYSCALL_DEFINE3(msgctl, int, msqid, int, cmd, struct msqid_ds __user *, buf)
tbuf.msg_qbytes = msq->q_qbytes;
tbuf.msg_lspid = msq->q_lspid;
tbuf.msg_lrpid = msq->q_lrpid;
- msg_unlock(msq);
+ msg_unlock(msq, &node);
if (copy_msqid_to_user(buf, &tbuf, version))
return -EFAULT;
return success_return;
@@ -574,7 +581,7 @@ SYSCALL_DEFINE3(msgctl, int, msqid, int, cmd, struct msqid_ds __user *, buf)
}

out_unlock:
- msg_unlock(msq);
+ msg_unlock(msq, &node);
return err;
}

@@ -642,6 +649,7 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext,
struct msg_msg *msg;
int err;
struct ipc_namespace *ns;
+ struct q_spinlock_node node;

ns = current->nsproxy->ipc_ns;

@@ -657,7 +665,7 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext,
msg->m_type = mtype;
msg->m_ts = msgsz;

- msq = msg_lock_check(ns, msqid);
+ msq = msg_lock_check(ns, msqid, &node);
if (IS_ERR(msq)) {
err = PTR_ERR(msq);
goto out_free;
@@ -686,10 +694,10 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext,
}
ss_add(msq, &s);
ipc_rcu_getref(msq);
- msg_unlock(msq);
+ msg_unlock(msq, &node);
schedule();

- ipc_lock_by_ptr(&msq->q_perm);
+ ipc_lock_by_ptr(&msq->q_perm, &node);
ipc_rcu_putref(msq);
if (msq->q_perm.deleted) {
err = -EIDRM;
@@ -719,7 +727,7 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext,
msg = NULL;

out_unlock_free:
- msg_unlock(msq);
+ msg_unlock(msq, &node);
out_free:
if (msg != NULL)
free_msg(msg);
@@ -762,13 +770,14 @@ long do_msgrcv(int msqid, long *pmtype, void __user *mtext,
struct msg_msg *msg;
int mode;
struct ipc_namespace *ns;
+ struct q_spinlock_node node;

if (msqid < 0 || (long) msgsz < 0)
return -EINVAL;
mode = convert_mode(&msgtyp, msgflg);
ns = current->nsproxy->ipc_ns;

- msq = msg_lock_check(ns, msqid);
+ msq = msg_lock_check(ns, msqid, &node);
if (IS_ERR(msq))
return PTR_ERR(msq);

@@ -819,7 +828,7 @@ long do_msgrcv(int msqid, long *pmtype, void __user *mtext,
atomic_sub(msg->m_ts, &ns->msg_bytes);
atomic_dec(&ns->msg_hdrs);
ss_wakeup(&msq->q_senders, 0);
- msg_unlock(msq);
+ msg_unlock(msq, &node);
break;
}
/* No message waiting. Wait for a message */
@@ -837,7 +846,7 @@ long do_msgrcv(int msqid, long *pmtype, void __user *mtext,
msr_d.r_maxsize = msgsz;
msr_d.r_msg = ERR_PTR(-EAGAIN);
current->state = TASK_INTERRUPTIBLE;
- msg_unlock(msq);
+ msg_unlock(msq, &node);

schedule();

@@ -876,7 +885,7 @@ long do_msgrcv(int msqid, long *pmtype, void __user *mtext,
/* Lockless receive, part 3:
* Acquire the queue spinlock.
*/
- ipc_lock_by_ptr(&msq->q_perm);
+ ipc_lock_by_ptr(&msq->q_perm, &node);
rcu_read_unlock();

/* Lockless receive, part 4:
@@ -890,7 +899,7 @@ long do_msgrcv(int msqid, long *pmtype, void __user *mtext,
if (signal_pending(current)) {
msg = ERR_PTR(-ERESTARTNOHAND);
out_unlock:
- msg_unlock(msq);
+ msg_unlock(msq, &node);
break;
}
}
diff --git a/ipc/namespace.c b/ipc/namespace.c
index f362298c5ce4..ba4f87c18870 100644
--- a/ipc/namespace.c
+++ b/ipc/namespace.c
@@ -70,11 +70,13 @@ struct ipc_namespace *copy_ipcs(unsigned long flags,
* Called for each kind of ipc when an ipc_namespace exits.
*/
void free_ipcs(struct ipc_namespace *ns, struct ipc_ids *ids,
- void (*free)(struct ipc_namespace *, struct kern_ipc_perm *))
+ void (*free)(struct ipc_namespace *, struct kern_ipc_perm *,
+ struct q_spinlock_node *))
{
struct kern_ipc_perm *perm;
int next_id;
int total, in_use;
+ struct q_spinlock_node node;

down_write(&ids->rw_mutex);

@@ -84,8 +86,8 @@ void free_ipcs(struct ipc_namespace *ns, struct ipc_ids *ids,
perm = idr_find(&ids->ipcs_idr, next_id);
if (perm == NULL)
continue;
- ipc_lock_by_ptr(perm);
- free(ns, perm);
+ ipc_lock_by_ptr(perm, &node);
+ free(ns, perm, &node);
total++;
}
up_write(&ids->rw_mutex);
diff --git a/ipc/sem.c b/ipc/sem.c
index 58d31f1c1eb5..84b7f3b2c632 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -138,11 +138,12 @@ struct sem_undo_list {

#define sem_ids(ns) ((ns)->ids[IPC_SEM_IDS])

-#define sem_unlock(sma) ipc_unlock(&(sma)->sem_perm)
+#define sem_unlock(sma,node) ipc_unlock(&(sma)->sem_perm, node)
#define sem_checkid(sma, semid) ipc_checkid(&sma->sem_perm, semid)

static int newary(struct ipc_namespace *, struct ipc_params *);
-static void freeary(struct ipc_namespace *, struct kern_ipc_perm *);
+static void freeary(struct ipc_namespace *, struct kern_ipc_perm *,
+ struct q_spinlock_node *);
#ifdef CONFIG_PROC_FS
static int sysvipc_sem_proc_show(struct seq_file *s, void *it);
#endif
@@ -194,9 +195,10 @@ void __init sem_init (void)
* sem_lock_(check_) routines are called in the paths where the rw_mutex
* is not held.
*/
-static inline struct sem_array *sem_lock(struct ipc_namespace *ns, int id)
+static inline struct sem_array *sem_lock(struct ipc_namespace *ns, int id,
+ struct q_spinlock_node *node)
{
- struct kern_ipc_perm *ipcp = ipc_lock(&sem_ids(ns), id);
+ struct kern_ipc_perm *ipcp = ipc_lock(&sem_ids(ns), id, node);

if (IS_ERR(ipcp))
return (struct sem_array *)ipcp;
@@ -205,9 +207,10 @@ static inline struct sem_array *sem_lock(struct ipc_namespace *ns, int id)
}

static inline struct sem_array *sem_lock_check(struct ipc_namespace *ns,
- int id)
+ int id,
+ struct q_spinlock_node *node)
{
- struct kern_ipc_perm *ipcp = ipc_lock_check(&sem_ids(ns), id);
+ struct kern_ipc_perm *ipcp = ipc_lock_check(&sem_ids(ns), id, node);

if (IS_ERR(ipcp))
return (struct sem_array *)ipcp;
@@ -215,23 +218,26 @@ static inline struct sem_array *sem_lock_check(struct ipc_namespace *ns,
return container_of(ipcp, struct sem_array, sem_perm);
}

-static inline void sem_lock_and_putref(struct sem_array *sma)
+static inline void sem_lock_and_putref(struct sem_array *sma,
+ struct q_spinlock_node *node)
{
- ipc_lock_by_ptr(&sma->sem_perm);
+ ipc_lock_by_ptr(&sma->sem_perm, node);
ipc_rcu_putref(sma);
}

-static inline void sem_getref_and_unlock(struct sem_array *sma)
+static inline void sem_getref_and_unlock(struct sem_array *sma,
+ struct q_spinlock_node *node)
{
ipc_rcu_getref(sma);
- ipc_unlock(&(sma)->sem_perm);
+ ipc_unlock(&(sma)->sem_perm, node);
}

static inline void sem_putref(struct sem_array *sma)
{
- ipc_lock_by_ptr(&sma->sem_perm);
+ struct q_spinlock_node node;
+ ipc_lock_by_ptr(&sma->sem_perm, &node);
ipc_rcu_putref(sma);
- ipc_unlock(&(sma)->sem_perm);
+ ipc_unlock(&(sma)->sem_perm, &node);
}

static inline void sem_rmid(struct ipc_namespace *ns, struct sem_array *s)
@@ -291,6 +297,7 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params)
int nsems = params->u.nsems;
int semflg = params->flg;
int i;
+ struct q_spinlock_node node;

if (!nsems)
return -EINVAL;
@@ -314,7 +321,7 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params)
return retval;
}

- id = ipc_addid(&sem_ids(ns), &sma->sem_perm, ns->sc_semmni);
+ id = ipc_addid(&sem_ids(ns), &sma->sem_perm, ns->sc_semmni, &node);
if (id < 0) {
security_sem_free(sma);
ipc_rcu_putref(sma);
@@ -332,7 +339,7 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params)
INIT_LIST_HEAD(&sma->list_id);
sma->sem_nsems = nsems;
sma->sem_ctime = get_seconds();
- sem_unlock(sma);
+ sem_unlock(sma, &node);

return sma->sem_perm.id;
}
@@ -739,7 +746,8 @@ static int count_semzcnt (struct sem_array * sma, ushort semnum)
* as a writer and the spinlock for this semaphore set hold. sem_ids.rw_mutex
* remains locked on exit.
*/
-static void freeary(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
+static void freeary(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp,
+ struct q_spinlock_node *node)
{
struct sem_undo *un, *tu;
struct sem_queue *q, *tq;
@@ -747,7 +755,7 @@ static void freeary(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
struct list_head tasks;

/* Free the existing undo structures for this semaphore set. */
- assert_spin_locked(&sma->sem_perm.lock);
+ assert_q_spin_locked(&sma->sem_perm.lock);
list_for_each_entry_safe(un, tu, &sma->list_id, list_id) {
list_del(&un->list_id);
spin_lock(&un->ulp->lock);
@@ -766,7 +774,7 @@ static void freeary(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)

/* Remove the semaphore set from the IDR */
sem_rmid(ns, sma);
- sem_unlock(sma);
+ sem_unlock(sma, node);

wake_up_sem_queue_do(&tasks);
ns->used_sems -= sma->sem_nsems;
@@ -803,6 +811,7 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid,
{
int err;
struct sem_array *sma;
+ struct q_spinlock_node node;

switch(cmd) {
case IPC_INFO:
@@ -845,12 +854,12 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid,
int id;

if (cmd == SEM_STAT) {
- sma = sem_lock(ns, semid);
+ sma = sem_lock(ns, semid, &node);
if (IS_ERR(sma))
return PTR_ERR(sma);
id = sma->sem_perm.id;
} else {
- sma = sem_lock_check(ns, semid);
+ sma = sem_lock_check(ns, semid, &node);
if (IS_ERR(sma))
return PTR_ERR(sma);
id = 0;
@@ -870,7 +879,7 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid,
tbuf.sem_otime = sma->sem_otime;
tbuf.sem_ctime = sma->sem_ctime;
tbuf.sem_nsems = sma->sem_nsems;
- sem_unlock(sma);
+ sem_unlock(sma, &node);
if (copy_semid_to_user (arg.buf, &tbuf, version))
return -EFAULT;
return id;
@@ -879,7 +888,7 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid,
return -EINVAL;
}
out_unlock:
- sem_unlock(sma);
+ sem_unlock(sma, &node);
return err;
}

@@ -893,8 +902,9 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
ushort* sem_io = fast_sem_io;
int nsems;
struct list_head tasks;
+ struct q_spinlock_node node;

- sma = sem_lock_check(ns, semid);
+ sma = sem_lock_check(ns, semid, &node);
if (IS_ERR(sma))
return PTR_ERR(sma);

@@ -918,7 +928,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
int i;

if(nsems > SEMMSL_FAST) {
- sem_getref_and_unlock(sma);
+ sem_getref_and_unlock(sma, &node);

sem_io = ipc_alloc(sizeof(ushort)*nsems);
if(sem_io == NULL) {
@@ -926,9 +936,9 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
return -ENOMEM;
}

- sem_lock_and_putref(sma);
+ sem_lock_and_putref(sma, &node);
if (sma->sem_perm.deleted) {
- sem_unlock(sma);
+ sem_unlock(sma, &node);
err = -EIDRM;
goto out_free;
}
@@ -936,7 +946,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,

for (i = 0; i < sma->sem_nsems; i++)
sem_io[i] = sma->sem_base[i].semval;
- sem_unlock(sma);
+ sem_unlock(sma, &node);
err = 0;
if(copy_to_user(array, sem_io, nsems*sizeof(ushort)))
err = -EFAULT;
@@ -947,7 +957,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
int i;
struct sem_undo *un;

- sem_getref_and_unlock(sma);
+ sem_getref_and_unlock(sma, &node);

if(nsems > SEMMSL_FAST) {
sem_io = ipc_alloc(sizeof(ushort)*nsems);
@@ -970,9 +980,9 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
goto out_free;
}
}
- sem_lock_and_putref(sma);
+ sem_lock_and_putref(sma, &node);
if (sma->sem_perm.deleted) {
- sem_unlock(sma);
+ sem_unlock(sma, &node);
err = -EIDRM;
goto out_free;
}
@@ -980,7 +990,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
for (i = 0; i < nsems; i++)
sma->sem_base[i].semval = sem_io[i];

- assert_spin_locked(&sma->sem_perm.lock);
+ assert_q_spin_locked(&sma->sem_perm.lock);
list_for_each_entry(un, &sma->list_id, list_id) {
for (i = 0; i < nsems; i++)
un->semadj[i] = 0;
@@ -1021,7 +1031,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
if (val > SEMVMX || val < 0)
goto out_unlock;

- assert_spin_locked(&sma->sem_perm.lock);
+ assert_q_spin_locked(&sma->sem_perm.lock);
list_for_each_entry(un, &sma->list_id, list_id)
un->semadj[semnum] = 0;

@@ -1035,7 +1045,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
}
}
out_unlock:
- sem_unlock(sma);
+ sem_unlock(sma, &node);
wake_up_sem_queue_do(&tasks);

out_free:
@@ -1082,6 +1092,7 @@ static int semctl_down(struct ipc_namespace *ns, int semid,
int err;
struct semid64_ds semid64;
struct kern_ipc_perm *ipcp;
+ struct q_spinlock_node node;

if(cmd == IPC_SET) {
if (copy_semid_from_user(&semid64, arg.buf, version))
@@ -1089,7 +1100,7 @@ static int semctl_down(struct ipc_namespace *ns, int semid,
}

ipcp = ipcctl_pre_down(ns, &sem_ids(ns), semid, cmd,
- &semid64.sem_perm, 0);
+ &semid64.sem_perm, 0, &node);
if (IS_ERR(ipcp))
return PTR_ERR(ipcp);

@@ -1101,7 +1112,7 @@ static int semctl_down(struct ipc_namespace *ns, int semid,

switch(cmd){
case IPC_RMID:
- freeary(ns, ipcp);
+ freeary(ns, ipcp, &node);
goto out_up;
case IPC_SET:
err = ipc_update_perm(&semid64.sem_perm, ipcp);
@@ -1114,7 +1125,7 @@ static int semctl_down(struct ipc_namespace *ns, int semid,
}

out_unlock:
- sem_unlock(sma);
+ sem_unlock(sma, &node);
out_up:
up_write(&sem_ids(ns).rw_mutex);
return err;
@@ -1237,6 +1248,7 @@ static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid)
struct sem_undo *un, *new;
int nsems;
int error;
+ struct q_spinlock_node node;

error = get_undo_list(&ulp);
if (error)
@@ -1252,12 +1264,12 @@ static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid)

/* no undo structure around - allocate one. */
/* step 1: figure out the size of the semaphore array */
- sma = sem_lock_check(ns, semid);
+ sma = sem_lock_check(ns, semid, &node);
if (IS_ERR(sma))
return ERR_CAST(sma);

nsems = sma->sem_nsems;
- sem_getref_and_unlock(sma);
+ sem_getref_and_unlock(sma, &node);

/* step 2: allocate new undo structure */
new = kzalloc(sizeof(struct sem_undo) + sizeof(short)*nsems, GFP_KERNEL);
@@ -1267,9 +1279,9 @@ static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid)
}

/* step 3: Acquire the lock on semaphore array */
- sem_lock_and_putref(sma);
+ sem_lock_and_putref(sma, &node);
if (sma->sem_perm.deleted) {
- sem_unlock(sma);
+ sem_unlock(sma, &node);
kfree(new);
un = ERR_PTR(-EIDRM);
goto out;
@@ -1290,14 +1302,14 @@ static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid)
new->semid = semid;
assert_spin_locked(&ulp->lock);
list_add_rcu(&new->list_proc, &ulp->list_proc);
- assert_spin_locked(&sma->sem_perm.lock);
+ assert_q_spin_locked(&sma->sem_perm.lock);
list_add(&new->list_id, &sma->list_id);
un = new;

success:
spin_unlock(&ulp->lock);
rcu_read_lock();
- sem_unlock(sma);
+ sem_unlock(sma, &node);
out:
return un;
}
@@ -1342,6 +1354,7 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
unsigned long jiffies_left = 0;
struct ipc_namespace *ns;
struct list_head tasks;
+ struct q_spinlock_node node;

ns = current->nsproxy->ipc_ns;

@@ -1392,7 +1405,7 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,

INIT_LIST_HEAD(&tasks);

- sma = sem_lock_check(ns, semid);
+ sma = sem_lock_check(ns, semid, &node);
if (IS_ERR(sma)) {
if (un)
rcu_read_unlock();
@@ -1477,7 +1490,7 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,

sleep_again:
current->state = TASK_INTERRUPTIBLE;
- sem_unlock(sma);
+ sem_unlock(sma, &node);

if (timeout)
jiffies_left = schedule_timeout(jiffies_left);
@@ -1499,7 +1512,7 @@ sleep_again:
goto out_free;
}

- sma = sem_lock(ns, semid);
+ sma = sem_lock(ns, semid, &node);

/*
* Wait until it's guaranteed that no wakeup_sem_queue_do() is ongoing.
@@ -1538,7 +1551,7 @@ sleep_again:
unlink_queue(sma, &queue);

out_unlock_free:
- sem_unlock(sma);
+ sem_unlock(sma, &node);

wake_up_sem_queue_do(&tasks);
out_free:
@@ -1604,6 +1617,7 @@ void exit_sem(struct task_struct *tsk)
struct list_head tasks;
int semid;
int i;
+ struct q_spinlock_node node;

rcu_read_lock();
un = list_entry_rcu(ulp->list_proc.next,
@@ -1617,7 +1631,7 @@ void exit_sem(struct task_struct *tsk)
if (semid == -1)
break;

- sma = sem_lock_check(tsk->nsproxy->ipc_ns, un->semid);
+ sma = sem_lock_check(tsk->nsproxy->ipc_ns, un->semid, &node);

/* exit_sem raced with IPC_RMID, nothing to do */
if (IS_ERR(sma))
@@ -1628,12 +1642,12 @@ void exit_sem(struct task_struct *tsk)
/* exit_sem raced with IPC_RMID+semget() that created
* exactly the same semid. Nothing to do.
*/
- sem_unlock(sma);
+ sem_unlock(sma, &node);
continue;
}

/* remove un from the linked lists */
- assert_spin_locked(&sma->sem_perm.lock);
+ assert_q_spin_locked(&sma->sem_perm.lock);
list_del(&un->list_id);

spin_lock(&ulp->lock);
@@ -1668,7 +1682,7 @@ void exit_sem(struct task_struct *tsk)
/* maybe some queued-up processes were waiting for this */
INIT_LIST_HEAD(&tasks);
do_smart_update(sma, NULL, 0, 1, &tasks);
- sem_unlock(sma);
+ sem_unlock(sma, &node);
wake_up_sem_queue_do(&tasks);

kfree_rcu(un, rcu);
diff --git a/ipc/shm.c b/ipc/shm.c
index dff40c9f73c9..67645b4de436 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -58,13 +58,14 @@ static const struct vm_operations_struct shm_vm_ops;

#define shm_ids(ns) ((ns)->ids[IPC_SHM_IDS])

-#define shm_unlock(shp) \
- ipc_unlock(&(shp)->shm_perm)
+#define shm_unlock(shp,node) \
+ ipc_unlock(&(shp)->shm_perm,node)

static int newseg(struct ipc_namespace *, struct ipc_params *);
static void shm_open(struct vm_area_struct *vma);
static void shm_close(struct vm_area_struct *vma);
-static void shm_destroy (struct ipc_namespace *ns, struct shmid_kernel *shp);
+static void shm_destroy (struct ipc_namespace *ns, struct shmid_kernel *shp,
+ struct q_spinlock_node *node);
#ifdef CONFIG_PROC_FS
static int sysvipc_shm_proc_show(struct seq_file *s, void *it);
#endif
@@ -83,7 +84,8 @@ void shm_init_ns(struct ipc_namespace *ns)
* Called with shm_ids.rw_mutex (writer) and the shp structure locked.
* Only shm_ids.rw_mutex remains locked on exit.
*/
-static void do_shm_rmid(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
+static void do_shm_rmid(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp,
+ struct q_spinlock_node *node)
{
struct shmid_kernel *shp;
shp = container_of(ipcp, struct shmid_kernel, shm_perm);
@@ -92,9 +94,9 @@ static void do_shm_rmid(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
shp->shm_perm.mode |= SHM_DEST;
/* Do not find it any more */
shp->shm_perm.key = IPC_PRIVATE;
- shm_unlock(shp);
+ shm_unlock(shp, node);
} else
- shm_destroy(ns, shp);
+ shm_destroy(ns, shp, node);
}

#ifdef CONFIG_IPC_NS
@@ -128,9 +130,10 @@ void __init shm_init (void)
* shm_lock_(check_) routines are called in the paths where the rw_mutex
* is not necessarily held.
*/
-static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id)
+static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id,
+ struct q_spinlock_node *node)
{
- struct kern_ipc_perm *ipcp = ipc_lock(&shm_ids(ns), id);
+ struct kern_ipc_perm *ipcp = ipc_lock(&shm_ids(ns), id, node);

if (IS_ERR(ipcp))
return (struct shmid_kernel *)ipcp;
@@ -138,16 +141,17 @@ static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id)
return container_of(ipcp, struct shmid_kernel, shm_perm);
}

-static inline void shm_lock_by_ptr(struct shmid_kernel *ipcp)
+static inline void shm_lock_by_ptr(struct shmid_kernel *ipcp,
+ struct q_spinlock_node *node)
{
- rcu_read_lock();
- spin_lock(&ipcp->shm_perm.lock);
+ ipc_lock_by_ptr(&ipcp->shm_perm, node);
}

static inline struct shmid_kernel *shm_lock_check(struct ipc_namespace *ns,
- int id)
+ int id,
+ struct q_spinlock_node *node)
{
- struct kern_ipc_perm *ipcp = ipc_lock_check(&shm_ids(ns), id);
+ struct kern_ipc_perm *ipcp = ipc_lock_check(&shm_ids(ns), id, node);

if (IS_ERR(ipcp))
return (struct shmid_kernel *)ipcp;
@@ -167,13 +171,14 @@ static void shm_open(struct vm_area_struct *vma)
struct file *file = vma->vm_file;
struct shm_file_data *sfd = shm_file_data(file);
struct shmid_kernel *shp;
+ struct q_spinlock_node node;

- shp = shm_lock(sfd->ns, sfd->id);
+ shp = shm_lock(sfd->ns, sfd->id, &node);
BUG_ON(IS_ERR(shp));
shp->shm_atim = get_seconds();
shp->shm_lprid = task_tgid_vnr(current);
shp->shm_nattch++;
- shm_unlock(shp);
+ shm_unlock(shp, &node);
}

/*
@@ -185,11 +190,12 @@ static void shm_open(struct vm_area_struct *vma)
* It has to be called with shp and shm_ids.rw_mutex (writer) locked,
* but returns with shp unlocked and freed.
*/
-static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp)
+static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp,
+ struct q_spinlock_node *node)
{
ns->shm_tot -= (shp->shm_segsz + PAGE_SIZE - 1) >> PAGE_SHIFT;
shm_rmid(ns, shp);
- shm_unlock(shp);
+ shm_unlock(shp, node);
if (!is_file_hugepages(shp->shm_file))
shmem_lock(shp->shm_file, 0, shp->mlock_user);
else if (shp->mlock_user)
@@ -229,18 +235,19 @@ static void shm_close(struct vm_area_struct *vma)
struct shm_file_data *sfd = shm_file_data(file);
struct shmid_kernel *shp;
struct ipc_namespace *ns = sfd->ns;
+ struct q_spinlock_node node;

down_write(&shm_ids(ns).rw_mutex);
/* remove from the list of attaches of the shm segment */
- shp = shm_lock(ns, sfd->id);
+ shp = shm_lock(ns, sfd->id, &node);
BUG_ON(IS_ERR(shp));
shp->shm_lprid = task_tgid_vnr(current);
shp->shm_dtim = get_seconds();
shp->shm_nattch--;
if (shm_may_destroy(ns, shp))
- shm_destroy(ns, shp);
+ shm_destroy(ns, shp, &node);
else
- shm_unlock(shp);
+ shm_unlock(shp, &node);
up_write(&shm_ids(ns).rw_mutex);
}

@@ -269,8 +276,9 @@ static int shm_try_destroy_current(int id, void *p, void *data)
return 0;

if (shm_may_destroy(ns, shp)) {
- shm_lock_by_ptr(shp);
- shm_destroy(ns, shp);
+ struct q_spinlock_node node;
+ shm_lock_by_ptr(shp, &node);
+ shm_destroy(ns, shp, &node);
}
return 0;
}
@@ -292,8 +300,9 @@ static int shm_try_destroy_orphaned(int id, void *p, void *data)
return 0;

if (shm_may_destroy(ns, shp)) {
- shm_lock_by_ptr(shp);
- shm_destroy(ns, shp);
+ struct q_spinlock_node node;
+ shm_lock_by_ptr(shp, &node);
+ shm_destroy(ns, shp, &node);
}
return 0;
}
@@ -467,6 +476,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
char name[13];
int id;
vm_flags_t acctflag = 0;
+ struct q_spinlock_node node;

if (size < SHMMIN || size > ns->shm_ctlmax)
return -EINVAL;
@@ -510,7 +520,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
if (IS_ERR(file))
goto no_file;

- id = ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni);
+ id = ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni, &node);
if (id < 0) {
error = id;
goto no_id;
@@ -532,7 +542,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)

ns->shm_tot += numpages;
error = shp->shm_perm.id;
- shm_unlock(shp);
+ shm_unlock(shp, &node);
return error;

no_id:
@@ -737,6 +747,7 @@ static int shmctl_down(struct ipc_namespace *ns, int shmid, int cmd,
struct shmid64_ds shmid64;
struct shmid_kernel *shp;
int err;
+ struct q_spinlock_node node;

if (cmd == IPC_SET) {
if (copy_shmid_from_user(&shmid64, buf, version))
@@ -744,7 +755,7 @@ static int shmctl_down(struct ipc_namespace *ns, int shmid, int cmd,
}

ipcp = ipcctl_pre_down(ns, &shm_ids(ns), shmid, cmd,
- &shmid64.shm_perm, 0);
+ &shmid64.shm_perm, 0, &node);
if (IS_ERR(ipcp))
return PTR_ERR(ipcp);

@@ -755,7 +766,7 @@ static int shmctl_down(struct ipc_namespace *ns, int shmid, int cmd,
goto out_unlock;
switch (cmd) {
case IPC_RMID:
- do_shm_rmid(ns, ipcp);
+ do_shm_rmid(ns, ipcp, &node);
goto out_up;
case IPC_SET:
err = ipc_update_perm(&shmid64.shm_perm, ipcp);
@@ -767,7 +778,7 @@ static int shmctl_down(struct ipc_namespace *ns, int shmid, int cmd,
err = -EINVAL;
}
out_unlock:
- shm_unlock(shp);
+ shm_unlock(shp, &node);
out_up:
up_write(&shm_ids(ns).rw_mutex);
return err;
@@ -778,6 +789,7 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
struct shmid_kernel *shp;
int err, version;
struct ipc_namespace *ns;
+ struct q_spinlock_node node;

if (cmd < 0 || shmid < 0) {
err = -EINVAL;
@@ -845,14 +857,14 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
int result;

if (cmd == SHM_STAT) {
- shp = shm_lock(ns, shmid);
+ shp = shm_lock(ns, shmid, &node);
if (IS_ERR(shp)) {
err = PTR_ERR(shp);
goto out;
}
result = shp->shm_perm.id;
} else {
- shp = shm_lock_check(ns, shmid);
+ shp = shm_lock_check(ns, shmid, &node);
if (IS_ERR(shp)) {
err = PTR_ERR(shp);
goto out;
@@ -874,7 +886,7 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
tbuf.shm_cpid = shp->shm_cprid;
tbuf.shm_lpid = shp->shm_lprid;
tbuf.shm_nattch = shp->shm_nattch;
- shm_unlock(shp);
+ shm_unlock(shp, &node);
if(copy_shmid_to_user (buf, &tbuf, version))
err = -EFAULT;
else
@@ -886,7 +898,7 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
{
struct file *shm_file;

- shp = shm_lock_check(ns, shmid);
+ shp = shm_lock_check(ns, shmid, &node);
if (IS_ERR(shp)) {
err = PTR_ERR(shp);
goto out;
@@ -929,7 +941,7 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
shp->shm_perm.mode &= ~SHM_LOCKED;
shp->mlock_user = NULL;
get_file(shm_file);
- shm_unlock(shp);
+ shm_unlock(shp, &node);
shmem_unlock_mapping(shm_file->f_mapping);
fput(shm_file);
goto out;
@@ -943,7 +955,7 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
}

out_unlock:
- shm_unlock(shp);
+ shm_unlock(shp, &node);
out:
return err;
}
@@ -971,6 +983,7 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr,
struct shm_file_data *sfd;
struct path path;
fmode_t f_mode;
+ struct q_spinlock_node node;

err = -EINVAL;
if (shmid < 0)
@@ -1012,7 +1025,7 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr,
* additional creator id...
*/
ns = current->nsproxy->ipc_ns;
- shp = shm_lock_check(ns, shmid);
+ shp = shm_lock_check(ns, shmid, &node);
if (IS_ERR(shp)) {
err = PTR_ERR(shp);
goto out;
@@ -1030,7 +1043,7 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr,
path_get(&path);
shp->shm_nattch++;
size = i_size_read(path.dentry->d_inode);
- shm_unlock(shp);
+ shm_unlock(shp, &node);

err = -ENOMEM;
sfd = kzalloc(sizeof(*sfd), GFP_KERNEL);
@@ -1082,20 +1095,20 @@ out_fput:

out_nattch:
down_write(&shm_ids(ns).rw_mutex);
- shp = shm_lock(ns, shmid);
+ shp = shm_lock(ns, shmid, &node);
BUG_ON(IS_ERR(shp));
shp->shm_nattch--;
if (shm_may_destroy(ns, shp))
- shm_destroy(ns, shp);
+ shm_destroy(ns, shp, &node);
else
- shm_unlock(shp);
+ shm_unlock(shp, &node);
up_write(&shm_ids(ns).rw_mutex);

out:
return err;

out_unlock:
- shm_unlock(shp);
+ shm_unlock(shp, &node);
goto out;

out_free:
diff --git a/ipc/util.c b/ipc/util.c
index 72fd0785ac94..b4232f0cb473 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -178,7 +178,8 @@ void __init ipc_init_proc_interface(const char *path, const char *header,
* If key is found ipc points to the owning ipc structure
*/

-static struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key)
+static struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key,
+ struct q_spinlock_node *node)
{
struct kern_ipc_perm *ipc;
int next_id;
@@ -195,7 +196,7 @@ static struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key)
continue;
}

- ipc_lock_by_ptr(ipc);
+ ipc_lock_by_ptr(ipc, node);
return ipc;
}

@@ -247,7 +248,8 @@ int ipc_get_maxid(struct ipc_ids *ids)
* Called with ipc_ids.rw_mutex held as a writer.
*/

-int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
+int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size,
+ struct q_spinlock_node *node)
{
kuid_t euid;
kgid_t egid;
@@ -259,14 +261,14 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
if (ids->in_use >= size)
return -ENOSPC;

- spin_lock_init(&new->lock);
+ q_spin_lock_init(&new->lock);
new->deleted = 0;
rcu_read_lock();
- spin_lock(&new->lock);
+ q_spin_lock(&new->lock, node);

err = idr_get_new(&ids->ipcs_idr, new, &id);
if (err) {
- spin_unlock(&new->lock);
+ q_spin_unlock(&new->lock, node);
rcu_read_unlock();
return err;
}
@@ -368,6 +370,7 @@ static int ipcget_public(struct ipc_namespace *ns, struct ipc_ids *ids,
struct kern_ipc_perm *ipcp;
int flg = params->flg;
int err;
+ struct q_spinlock_node node;
retry:
err = idr_pre_get(&ids->ipcs_idr, GFP_KERNEL);

@@ -376,7 +379,7 @@ retry:
* a new entry + read locks are not "upgradable"
*/
down_write(&ids->rw_mutex);
- ipcp = ipc_findkey(ids, params->key);
+ ipcp = ipc_findkey(ids, params->key, &node);
if (ipcp == NULL) {
/* key not used */
if (!(flg & IPC_CREAT))
@@ -401,7 +404,7 @@ retry:
*/
err = ipc_check_perms(ns, ipcp, ops, params);
}
- ipc_unlock(ipcp);
+ ipc_unlock(ipcp, &node);
}
up_write(&ids->rw_mutex);

@@ -681,7 +684,8 @@ void ipc64_perm_to_ipc_perm (struct ipc64_perm *in, struct ipc_perm *out)
* The ipc object is locked on exit.
*/

-struct kern_ipc_perm *ipc_lock(struct ipc_ids *ids, int id)
+struct kern_ipc_perm *ipc_lock(struct ipc_ids *ids, int id,
+ struct q_spinlock_node *node)
{
struct kern_ipc_perm *out;
int lid = ipcid_to_idx(id);
@@ -693,13 +697,13 @@ struct kern_ipc_perm *ipc_lock(struct ipc_ids *ids, int id)
return ERR_PTR(-EINVAL);
}

- spin_lock(&out->lock);
+ q_spin_lock(&out->lock, node);

/* ipc_rmid() may have already freed the ID while ipc_lock
* was spinning: here verify that the structure is still valid
*/
if (out->deleted) {
- spin_unlock(&out->lock);
+ q_spin_unlock(&out->lock, node);
rcu_read_unlock();
return ERR_PTR(-EINVAL);
}
@@ -707,16 +711,17 @@ struct kern_ipc_perm *ipc_lock(struct ipc_ids *ids, int id)
return out;
}

-struct kern_ipc_perm *ipc_lock_check(struct ipc_ids *ids, int id)
+struct kern_ipc_perm *ipc_lock_check(struct ipc_ids *ids, int id,
+ struct q_spinlock_node *node)
{
struct kern_ipc_perm *out;

- out = ipc_lock(ids, id);
+ out = ipc_lock(ids, id, node);
if (IS_ERR(out))
return out;

if (ipc_checkid(out, id)) {
- ipc_unlock(out);
+ ipc_unlock(out, node);
return ERR_PTR(-EIDRM);
}

@@ -781,14 +786,15 @@ int ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out)
*/
struct kern_ipc_perm *ipcctl_pre_down(struct ipc_namespace *ns,
struct ipc_ids *ids, int id, int cmd,
- struct ipc64_perm *perm, int extra_perm)
+ struct ipc64_perm *perm, int extra_perm,
+ struct q_spinlock_node *node)
{
struct kern_ipc_perm *ipcp;
kuid_t euid;
int err;

down_write(&ids->rw_mutex);
- ipcp = ipc_lock_check(ids, id);
+ ipcp = ipc_lock_check(ids, id, node);
if (IS_ERR(ipcp)) {
err = PTR_ERR(ipcp);
goto out_up;
@@ -805,7 +811,7 @@ struct kern_ipc_perm *ipcctl_pre_down(struct ipc_namespace *ns,
return ipcp;

err = -EPERM;
- ipc_unlock(ipcp);
+ ipc_unlock(ipcp, node);
out_up:
up_write(&ids->rw_mutex);
return ERR_PTR(err);
@@ -839,13 +845,15 @@ int ipc_parse_version (int *cmd)
struct ipc_proc_iter {
struct ipc_namespace *ns;
struct ipc_proc_iface *iface;
+ struct q_spinlock_node node;
};

/*
* This routine locks the ipc structure found at least at position pos.
*/
static struct kern_ipc_perm *sysvipc_find_ipc(struct ipc_ids *ids, loff_t pos,
- loff_t *new_pos)
+ loff_t *new_pos,
+ struct q_spinlock_node *node)
{
struct kern_ipc_perm *ipc;
int total, id;
@@ -864,7 +872,7 @@ static struct kern_ipc_perm *sysvipc_find_ipc(struct ipc_ids *ids, loff_t pos,
ipc = idr_find(&ids->ipcs_idr, pos);
if (ipc != NULL) {
*new_pos = pos + 1;
- ipc_lock_by_ptr(ipc);
+ ipc_lock_by_ptr(ipc, node);
return ipc;
}
}
@@ -881,9 +889,10 @@ static void *sysvipc_proc_next(struct seq_file *s, void *it, loff_t *pos)

/* If we had an ipc id locked before, unlock it */
if (ipc && ipc != SEQ_START_TOKEN)
- ipc_unlock(ipc);
+ ipc_unlock(ipc, &iter->node);

- return sysvipc_find_ipc(&iter->ns->ids[iface->ids], *pos, pos);
+ return sysvipc_find_ipc(&iter->ns->ids[iface->ids], *pos, pos,
+ &iter->node);
}

/*
@@ -913,7 +922,7 @@ static void *sysvipc_proc_start(struct seq_file *s, loff_t *pos)
return SEQ_START_TOKEN;

/* Find the (pos-1)th ipc */
- return sysvipc_find_ipc(ids, *pos - 1, pos);
+ return sysvipc_find_ipc(ids, *pos - 1, pos, &iter->node);
}

static void sysvipc_proc_stop(struct seq_file *s, void *it)
@@ -925,7 +934,7 @@ static void sysvipc_proc_stop(struct seq_file *s, void *it)

/* If we had a locked structure, release it */
if (ipc && ipc != SEQ_START_TOKEN)
- ipc_unlock(ipc);
+ ipc_unlock(ipc, &iter->node);

ids = &iter->ns->ids[iface->ids];
/* Release the lock we took in start() */
diff --git a/ipc/util.h b/ipc/util.h
index c8fe2f7631e9..f03c36188cc3 100644
--- a/ipc/util.h
+++ b/ipc/util.h
@@ -94,7 +94,8 @@ void __init ipc_init_proc_interface(const char *path, const char *header,
#define ipcid_to_idx(id) ((id) % SEQ_MULTIPLIER)

/* must be called with ids->rw_mutex acquired for writing */
-int ipc_addid(struct ipc_ids *, struct kern_ipc_perm *, int);
+int ipc_addid(struct ipc_ids *, struct kern_ipc_perm *, int,
+ struct q_spinlock_node *);

/* must be called with ids->rw_mutex acquired for reading */
int ipc_get_maxid(struct ipc_ids *);
@@ -121,14 +122,16 @@ void* ipc_rcu_alloc(int size);
void ipc_rcu_getref(void *ptr);
void ipc_rcu_putref(void *ptr);

-struct kern_ipc_perm *ipc_lock(struct ipc_ids *, int);
+struct kern_ipc_perm *ipc_lock(struct ipc_ids *, int,
+ struct q_spinlock_node *);

void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out);
void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out);
int ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out);
struct kern_ipc_perm *ipcctl_pre_down(struct ipc_namespace *ns,
struct ipc_ids *ids, int id, int cmd,
- struct ipc64_perm *perm, int extra_perm);
+ struct ipc64_perm *perm, int extra_perm,
+ struct q_spinlock_node *node);

#ifndef CONFIG_ARCH_WANT_IPC_PARSE_VERSION
/* On IA-64, we always use the "64-bit version" of the IPC structures. */
@@ -158,21 +161,25 @@ static inline int ipc_checkid(struct kern_ipc_perm *ipcp, int uid)
return 0;
}

-static inline void ipc_lock_by_ptr(struct kern_ipc_perm *perm)
+static inline void ipc_lock_by_ptr(struct kern_ipc_perm *perm,
+ struct q_spinlock_node *node)
{
rcu_read_lock();
- spin_lock(&perm->lock);
+ q_spin_lock(&perm->lock, node);
}

-static inline void ipc_unlock(struct kern_ipc_perm *perm)
+static inline void ipc_unlock(struct kern_ipc_perm *perm,
+ struct q_spinlock_node *node)
{
- spin_unlock(&perm->lock);
+ q_spin_unlock(&perm->lock, node);
rcu_read_unlock();
}

-struct kern_ipc_perm *ipc_lock_check(struct ipc_ids *ids, int id);
+struct kern_ipc_perm *ipc_lock_check(struct ipc_ids *ids, int id,
+ struct q_spinlock_node *node);
int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids,
struct ipc_ops *ops, struct ipc_params *params);
void free_ipcs(struct ipc_namespace *ns, struct ipc_ids *ids,
- void (*free)(struct ipc_namespace *, struct kern_ipc_perm *));
+ void (*free)(struct ipc_namespace *, struct kern_ipc_perm *,
+ struct q_spinlock_node *));
#endif
--
1.7.7.3

\
 
 \ /
  Last update: 2013-01-23 00:43    [W:0.476 / U:0.744 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site