summaryrefslogtreecommitdiffstats
path: root/ipc
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1997-04-29 21:13:14 +0000
committer <ralf@linux-mips.org>1997-04-29 21:13:14 +0000
commit19c9bba94152148523ba0f7ef7cffe3d45656b11 (patch)
tree40b1cb534496a7f1ca0f5c314a523c69f1fee464 /ipc
parent7206675c40394c78a90e74812bbdbf8cf3cca1be (diff)
Import of Linux/MIPS 2.1.36
Diffstat (limited to 'ipc')
-rw-r--r--ipc/msg.c133
-rw-r--r--ipc/sem.c187
-rw-r--r--ipc/shm.c195
3 files changed, 322 insertions, 193 deletions
diff --git a/ipc/msg.c b/ipc/msg.c
index 0ed1eb6a6..fcef8357f 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -15,6 +15,8 @@
#include <linux/malloc.h>
#include <linux/kerneld.h>
#include <linux/interrupt.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
#include <asm/uaccess.h>
@@ -135,7 +137,7 @@ static int real_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg
return -EAGAIN;
if (current->signal & ~current->blocked)
return -EINTR;
- if (intr_count) {
+ if (in_interrupt()) {
/* Very unlikely, but better safe than sorry */
printk(KERN_WARNING "Ouch, kerneld:msgsnd buffers full!\n");
return -EINTR;
@@ -393,15 +395,25 @@ static int real_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgty
asmlinkage int sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg)
{
+ int ret;
+
/* IPC_KERNELD is used as a marker for kernel level calls */
- return real_msgsnd(msqid, msgp, msgsz, msgflg & ~IPC_KERNELD);
+ lock_kernel();
+ ret = real_msgsnd(msqid, msgp, msgsz, msgflg & ~IPC_KERNELD);
+ unlock_kernel();
+ return ret;
}
asmlinkage int sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz,
long msgtyp, int msgflg)
{
+ int ret;
+
/* IPC_KERNELD is used as a marker for kernel level calls */
- return real_msgrcv (msqid, msgp, msgsz, msgtyp, msgflg & ~IPC_KERNELD);
+ lock_kernel();
+ ret = real_msgrcv (msqid, msgp, msgsz, msgtyp, msgflg & ~IPC_KERNELD);
+ unlock_kernel();
+ return ret;
}
static int findkey (key_t key)
@@ -463,51 +475,60 @@ found:
asmlinkage int sys_msgget (key_t key, int msgflg)
{
- int id;
+ int id, ret = -EPERM;
struct msqid_ds *msq;
/*
* If the IPC_KERNELD flag is set, the key is forced to IPC_PRIVATE,
* and a designated kerneld message queue is created/referred to
*/
+ lock_kernel();
if ((msgflg & IPC_KERNELD)) {
int i;
if (!suser())
- return -EPERM;
+ goto out;
#ifdef NEW_KERNELD_PROTOCOL
if ((msgflg & IPC_KERNELD) == OLDIPC_KERNELD) {
printk(KERN_ALERT "Please recompile your kerneld daemons!\n");
- return -EPERM;
+ goto out;
}
#endif
+ ret = -ENOSPC;
if ((kerneld_msqid == -1) && (kerneld_msqid =
newque(IPC_PRIVATE, msgflg & S_IRWXU)) < 0)
- return -ENOSPC;
+ goto out;
for (i = 0; i < MAX_KERNELDS; ++i) {
if (kerneld_arr[i] == 0) {
kerneld_arr[i] = current->pid;
++n_kernelds;
- return kerneld_msqid;
+ ret = kerneld_msqid;
+ goto out;
}
}
- return -ENOSPC;
+ goto out;
}
/* else it is a "normal" request */
if (key == IPC_PRIVATE)
- return newque(key, msgflg);
- if ((id = findkey (key)) == -1) { /* key not used */
+ ret = newque(key, msgflg);
+ else if ((id = findkey (key)) == -1) { /* key not used */
if (!(msgflg & IPC_CREAT))
- return -ENOENT;
- return newque(key, msgflg);
+ ret = -ENOENT;
+ else
+ ret = newque(key, msgflg);
+ } else if (msgflg & IPC_CREAT && msgflg & IPC_EXCL) {
+ ret = -EEXIST;
+ } else {
+ msq = msgque[id];
+ if (msq == IPC_UNUSED || msq == IPC_NOID)
+ ret = -EIDRM;
+ else if (ipcperms(&msq->msg_perm, msgflg))
+ ret = -EACCES;
+ else
+ ret = (unsigned int) msq->msg_perm.seq * MSGMNI + id;
}
- if (msgflg & IPC_CREAT && msgflg & IPC_EXCL)
- return -EEXIST;
- msq = msgque[id];
- if (msq == IPC_UNUSED || msq == IPC_NOID)
- return -EIDRM;
- if (ipcperms(&msq->msg_perm, msgflg))
- return -EACCES;
- return (unsigned int) msq->msg_perm.seq * MSGMNI + id;
+out:
+ unlock_kernel();
+ return ret;
}
static void freeque (int id)
@@ -537,18 +558,20 @@ static void freeque (int id)
asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf)
{
- int id, err;
+ int id, err = -EINVAL;
struct msqid_ds *msq;
struct msqid_ds tbuf;
struct ipc_perm *ipcp;
+ lock_kernel();
if (msqid < 0 || cmd < 0)
- return -EINVAL;
+ goto out;
+ err = -EFAULT;
switch (cmd) {
case IPC_INFO:
case MSG_INFO:
if (!buf)
- return -EFAULT;
+ goto out;
{
struct msginfo msginfo;
msginfo.msgmni = MSGMNI;
@@ -566,23 +589,26 @@ asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf)
}
err = verify_area (VERIFY_WRITE, buf, sizeof (struct msginfo));
if (err)
- return err;
+ goto out;
copy_to_user (buf, &msginfo, sizeof(struct msginfo));
- return max_msqid;
+ err = max_msqid;
+ goto out;
}
case MSG_STAT:
if (!buf)
- return -EFAULT;
+ goto out;
err = verify_area (VERIFY_WRITE, buf, sizeof (*buf));
if (err)
- return err;
+ goto out;
+ err = -EINVAL;
if (msqid > max_msqid)
- return -EINVAL;
+ goto out;
msq = msgque[msqid];
if (msq == IPC_UNUSED || msq == IPC_NOID)
- return -EINVAL;
+ goto out;
+ err = -EACCES;
if (ipcperms (&msq->msg_perm, S_IRUGO))
- return -EACCES;
+ goto out;
id = (unsigned int) msq->msg_perm.seq * MSGMNI + msqid;
tbuf.msg_perm = msq->msg_perm;
tbuf.msg_stime = msq->msg_stime;
@@ -594,36 +620,40 @@ asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf)
tbuf.msg_lspid = msq->msg_lspid;
tbuf.msg_lrpid = msq->msg_lrpid;
copy_to_user (buf, &tbuf, sizeof(*buf));
- return id;
+ err = id;
+ goto out;
case IPC_SET:
if (!buf)
- return -EFAULT;
+ goto out;
err = verify_area (VERIFY_READ, buf, sizeof (*buf));
if (err)
- return err;
+ goto out;
copy_from_user (&tbuf, buf, sizeof (*buf));
break;
case IPC_STAT:
if (!buf)
- return -EFAULT;
+ goto out;
err = verify_area (VERIFY_WRITE, buf, sizeof(*buf));
if (err)
- return err;
+ goto out;
break;
}
id = (unsigned int) msqid % MSGMNI;
msq = msgque [id];
+ err = -EINVAL;
if (msq == IPC_UNUSED || msq == IPC_NOID)
- return -EINVAL;
+ goto out;
+ err = -EIDRM;
if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI)
- return -EIDRM;
+ goto out;
ipcp = &msq->msg_perm;
switch (cmd) {
case IPC_STAT:
+ err = -EACCES;
if (ipcperms (ipcp, S_IRUGO))
- return -EACCES;
+ goto out;
tbuf.msg_perm = msq->msg_perm;
tbuf.msg_stime = msq->msg_stime;
tbuf.msg_rtime = msq->msg_rtime;
@@ -634,24 +664,28 @@ asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf)
tbuf.msg_lspid = msq->msg_lspid;
tbuf.msg_lrpid = msq->msg_lrpid;
copy_to_user (buf, &tbuf, sizeof (*buf));
- return 0;
+ err = 0;
+ goto out;
case IPC_SET:
+ err = -EPERM;
if (!suser() && current->euid != ipcp->cuid &&
current->euid != ipcp->uid)
- return -EPERM;
+ goto out;
if (tbuf.msg_qbytes > MSGMNB && !suser())
- return -EPERM;
+ goto out;
msq->msg_qbytes = tbuf.msg_qbytes;
ipcp->uid = tbuf.msg_perm.uid;
ipcp->gid = tbuf.msg_perm.gid;
ipcp->mode = (ipcp->mode & ~S_IRWXUGO) |
(S_IRWXUGO & tbuf.msg_perm.mode);
msq->msg_ctime = CURRENT_TIME;
- return 0;
+ err = 0;
+ goto out;
case IPC_RMID:
+ err = -EPERM;
if (!suser() && current->euid != ipcp->cuid &&
current->euid != ipcp->uid)
- return -EPERM;
+ goto out;
/*
* There is only one kerneld message queue,
* mark it as non-existent
@@ -659,10 +693,15 @@ asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf)
if ((kerneld_msqid >= 0) && (msqid == kerneld_msqid))
kerneld_msqid = -1;
freeque (id);
- return 0;
+ err = 0;
+ goto out;
default:
- return -EINVAL;
+ err = -EINVAL;
+ goto out;
}
+out:
+ unlock_kernel();
+ return err;
}
/*
@@ -735,7 +774,7 @@ int kerneld_send(int msgtype, int ret_size, int msgsz,
return -ENODEV;
/* Do not wait for an answer at interrupt-time! */
- if (intr_count)
+ if (in_interrupt())
ret_size &= ~KERNELD_WAIT;
#ifdef NEW_KERNELD_PROTOCOL
else
diff --git a/ipc/sem.c b/ipc/sem.c
index fb79d6004..8aecbfb48 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -38,6 +38,8 @@
#include <linux/ipc.h>
#include <linux/stat.h>
#include <linux/malloc.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
#include <asm/uaccess.h>
@@ -130,26 +132,33 @@ found:
asmlinkage int sys_semget (key_t key, int nsems, int semflg)
{
- int id;
+ int id, err = -EINVAL;
struct semid_ds *sma;
+ lock_kernel();
if (nsems < 0 || nsems > SEMMSL)
- return -EINVAL;
- if (key == IPC_PRIVATE)
- return newary(key, nsems, semflg);
- if ((id = findkey (key)) == -1) { /* key not used */
+ goto out;
+ if (key == IPC_PRIVATE) {
+ err = newary(key, nsems, semflg);
+ } else if ((id = findkey (key)) == -1) { /* key not used */
if (!(semflg & IPC_CREAT))
- return -ENOENT;
- return newary(key, nsems, semflg);
+ err = -ENOENT;
+ else
+ err = newary(key, nsems, semflg);
+ } else if (semflg & IPC_CREAT && semflg & IPC_EXCL) {
+ err = -EEXIST;
+ } else {
+ sma = semary[id];
+ if (nsems > sma->sem_nsems)
+ err = -EINVAL;
+ else if (ipcperms(&sma->sem_perm, semflg))
+ err = -EACCES;
+ else
+ err = (int) sma->sem_perm.seq * SEMMNI + id;
}
- if (semflg & IPC_CREAT && semflg & IPC_EXCL)
- return -EEXIST;
- sma = semary[id];
- if (nsems > sma->sem_nsems)
- return -EINVAL;
- if (ipcperms(&sma->sem_perm, semflg))
- return -EACCES;
- return (unsigned int) sma->sem_perm.seq * SEMMNI + id;
+out:
+ unlock_kernel();
+ return err;
}
/* Manage the doubly linked list sma->sem_pending as a FIFO:
@@ -368,9 +377,11 @@ asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg)
unsigned int nsems;
ushort *array = NULL;
ushort sem_io[SEMMSL];
+ int err = -EINVAL;
+ lock_kernel();
if (semid < 0 || semnum < 0 || cmd < 0)
- return -EINVAL;
+ goto out;
switch (cmd) {
case IPC_INFO:
@@ -391,42 +402,48 @@ asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg)
seminfo.semusz = used_semids;
seminfo.semaem = used_sems;
}
- i = verify_area(VERIFY_WRITE, tmp, sizeof(struct seminfo));
- if (i)
- return i;
+ err = verify_area(VERIFY_WRITE, tmp, sizeof(struct seminfo));
+ if (err)
+ goto out;
copy_to_user (tmp, &seminfo, sizeof(struct seminfo));
- return max_semid;
+ err = max_semid;
+ goto out;
}
case SEM_STAT:
buf = arg.buf;
- i = verify_area (VERIFY_WRITE, buf, sizeof (*buf));
- if (i)
- return i;
+ err = verify_area (VERIFY_WRITE, buf, sizeof (*buf));
+ if (err)
+ goto out;
+ err = -EINVAL;
if (semid > max_semid)
- return -EINVAL;
+ goto out;
sma = semary[semid];
if (sma == IPC_UNUSED || sma == IPC_NOID)
- return -EINVAL;
+ goto out;
+ err = -EACCES;
if (ipcperms (&sma->sem_perm, S_IRUGO))
- return -EACCES;
+ goto out;
id = (unsigned int) sma->sem_perm.seq * SEMMNI + semid;
tbuf.sem_perm = sma->sem_perm;
tbuf.sem_otime = sma->sem_otime;
tbuf.sem_ctime = sma->sem_ctime;
tbuf.sem_nsems = sma->sem_nsems;
copy_to_user (buf, &tbuf, sizeof(*buf));
- return id;
+ err = id;
+ goto out;
}
id = (unsigned int) semid % SEMMNI;
sma = semary [id];
+ err = -EINVAL;
if (sma == IPC_UNUSED || sma == IPC_NOID)
- return -EINVAL;
+ goto out;
ipcp = &sma->sem_perm;
nsems = sma->sem_nsems;
+ err = -EIDRM;
if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI)
- return -EIDRM;
+ goto out;
switch (cmd) {
case GETVAL:
@@ -434,8 +451,9 @@ asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg)
case GETNCNT:
case GETZCNT:
case SETVAL:
+ err = -EINVAL;
if (semnum >= nsems)
- return -EINVAL;
+ goto out;
curr = &sma->sem_base[semnum];
break;
}
@@ -446,8 +464,9 @@ asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg)
case GETNCNT:
case GETZCNT:
case GETALL:
+ err = -EACCES;
if (ipcperms (ipcp, S_IRUGO))
- return -EACCES;
+ goto out;
switch (cmd) {
case GETVAL : return curr->semval;
case GETPID : return curr->sempid;
@@ -455,60 +474,68 @@ asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg)
case GETZCNT: return count_semzcnt(sma,semnum);
case GETALL:
array = arg.array;
- i = verify_area (VERIFY_WRITE, array, nsems*sizeof(ushort));
- if (i)
- return i;
+ err = verify_area (VERIFY_WRITE, array, nsems*sizeof(ushort));
+ if (err)
+ goto out;
}
break;
case SETVAL:
val = arg.val;
+ err = -ERANGE;
if (val > SEMVMX || val < 0)
- return -ERANGE;
+ goto out;
break;
case IPC_RMID:
if (suser() || current->euid == ipcp->cuid || current->euid == ipcp->uid) {
freeary (id);
- return 0;
+ err = 0;
+ goto out;
}
- return -EPERM;
+ err = -EPERM;
+ goto out;
case SETALL: /* arg is a pointer to an array of ushort */
array = arg.array;
- if ((i = verify_area (VERIFY_READ, array, nsems*sizeof(ushort))))
- return i;
+ if ((err = verify_area (VERIFY_READ, array, nsems*sizeof(ushort))))
+ goto out;
copy_from_user (sem_io, array, nsems*sizeof(ushort));
for (i = 0; i < nsems; i++)
- if (sem_io[i] > SEMVMX)
- return -ERANGE;
+ if (sem_io[i] > SEMVMX) {
+ err = -ERANGE;
+ goto out;
+ }
break;
case IPC_STAT:
buf = arg.buf;
- if ((i = verify_area (VERIFY_WRITE, buf, sizeof(*buf))))
- return i;
+ if ((err = verify_area (VERIFY_WRITE, buf, sizeof(*buf))))
+ goto out;
break;
case IPC_SET:
buf = arg.buf;
- if ((i = verify_area (VERIFY_READ, buf, sizeof (*buf))))
- return i;
+ if ((err = verify_area (VERIFY_READ, buf, sizeof (*buf))))
+ goto out;
copy_from_user (&tbuf, buf, sizeof (*buf));
break;
}
+ err = -EIDRM;
if (semary[id] == IPC_UNUSED || semary[id] == IPC_NOID)
- return -EIDRM;
+ goto out;
if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI)
- return -EIDRM;
+ goto out;
switch (cmd) {
case GETALL:
+ err = -EACCES;
if (ipcperms (ipcp, S_IRUGO))
- return -EACCES;
+ goto out;
for (i = 0; i < sma->sem_nsems; i++)
sem_io[i] = sma->sem_base[i].semval;
copy_to_user (array, sem_io, nsems*sizeof(ushort));
break;
case SETVAL:
+ err = -EACCES;
if (ipcperms (ipcp, S_IWUGO))
- return -EACCES;
+ goto out;
for (un = sma->undo; un; un = un->id_next)
un->semadj[semnum] = 0;
curr->semval = val;
@@ -523,12 +550,15 @@ asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg)
ipcp->mode = (ipcp->mode & ~S_IRWXUGO)
| (tbuf.sem_perm.mode & S_IRWXUGO);
sma->sem_ctime = CURRENT_TIME;
- return 0;
+ err = 0;
+ goto out;
}
- return -EPERM;
+ err = -EPERM;
+ goto out;
case IPC_STAT:
+ err = -EACCES;
if (ipcperms (ipcp, S_IRUGO))
- return -EACCES;
+ goto out;
tbuf.sem_perm = sma->sem_perm;
tbuf.sem_otime = sma->sem_otime;
tbuf.sem_ctime = sma->sem_ctime;
@@ -536,8 +566,9 @@ asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg)
copy_to_user (buf, &tbuf, sizeof(*buf));
break;
case SETALL:
+ err = -EACCES;
if (ipcperms (ipcp, S_IWUGO))
- return -EACCES;
+ goto out;
for (i = 0; i < nsems; i++)
sma->sem_base[i].semval = sem_io[i];
for (un = sma->undo; un; un = un->id_next)
@@ -548,47 +579,58 @@ asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg)
update_queue(sma);
break;
default:
- return -EINVAL;
+ err = -EINVAL;
+ goto out;
}
- return 0;
+ err = 0;
+out:
+ unlock_kernel();
+ return err;
}
asmlinkage int sys_semop (int semid, struct sembuf *tsops, unsigned nsops)
{
- int i, id, size, error;
+ int i, id, size, error = -EINVAL;
struct semid_ds *sma;
struct sembuf sops[SEMOPM], *sop;
struct sem_undo *un;
int undos = 0, alter = 0;
+ lock_kernel();
if (nsops < 1 || semid < 0)
- return -EINVAL;
+ goto out;
+ error = -E2BIG;
if (nsops > SEMOPM)
- return -E2BIG;
+ goto out;
+ error = -EFAULT;
if (!tsops)
- return -EFAULT;
+ goto out;
if ((i = verify_area (VERIFY_READ, tsops, nsops * sizeof(*tsops))))
- return i;
+ goto out;
copy_from_user (sops, tsops, nsops * sizeof(*tsops));
id = (unsigned int) semid % SEMMNI;
+ error = -EINVAL;
if ((sma = semary[id]) == IPC_UNUSED || sma == IPC_NOID)
- return -EINVAL;
+ goto out;
+ error = -EIDRM;
if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI)
- return -EIDRM;
+ goto out;
for (i = 0; i < nsops; i++) {
sop = &sops[i];
+ error = -EFBIG;
if (sop->sem_num >= sma->sem_nsems)
- return -EFBIG;
+ goto out;
if (sop->sem_flg & SEM_UNDO)
undos++;
if (sop->sem_op)
alter++;
}
+ error = -EACCES;
if (ipcperms(&sma->sem_perm, alter ? S_IWUGO : S_IRUGO))
- return -EACCES;
+ goto out;
error = try_semop(sma, sops, nsops);
if (error < 0)
- return error;
+ goto out;
if (undos) {
/* Make sure we have an undo structure
* for this process and this semaphore set.
@@ -599,8 +641,10 @@ asmlinkage int sys_semop (int semid, struct sembuf *tsops, unsigned nsops)
if (!un) {
size = sizeof(struct sem_undo) + sizeof(short)*sma->sem_nsems;
un = (struct sem_undo *) kmalloc(size, GFP_ATOMIC);
- if (!un)
- return -ENOMEM;
+ if (!un) {
+ error = -ENOMEM;
+ goto out;
+ }
memset(un, 0, size);
un->semadj = (short *) &un[1];
un->semid = semid;
@@ -616,7 +660,7 @@ asmlinkage int sys_semop (int semid, struct sembuf *tsops, unsigned nsops)
error = do_semop(sma, sops, nsops, un, current->pid);
/* maybe some queued-up processes were waiting for this */
update_queue(sma);
- return error;
+ goto out;
} else {
/* We need to sleep on this operation, so we put the current
* task into the pending queue and go to sleep.
@@ -639,12 +683,15 @@ asmlinkage int sys_semop (int semid, struct sembuf *tsops, unsigned nsops)
*/
if (!queue.prev) {
/* operation is finished, update_queue() removed us */
- return queue.status;
+ error = queue.status;
} else {
remove_from_queue(sma,&queue);
- return -EINTR;
+ error = -EINTR;
}
}
+out:
+ unlock_kernel();
+ return error;
}
/*
diff --git a/ipc/shm.c b/ipc/shm.c
index ec408ed62..ab5974fed 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -8,11 +8,14 @@
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/mm.h>
+#include <linux/slab.h>
#include <linux/ipc.h>
#include <linux/shm.h>
#include <linux/stat.h>
#include <linux/malloc.h>
#include <linux/swap.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
@@ -130,27 +133,33 @@ found:
asmlinkage int sys_shmget (key_t key, int size, int shmflg)
{
struct shmid_ds *shp;
- int id = 0;
-
- if (size < 0 || size > SHMMAX)
- return -EINVAL;
- if (key == IPC_PRIVATE)
- return newseg(key, shmflg, size);
- if ((id = findkey (key)) == -1) {
+ int err, id = 0;
+
+ lock_kernel();
+ if (size < 0 || size > SHMMAX) {
+ err = -EINVAL;
+ } else if (key == IPC_PRIVATE) {
+ err = newseg(key, shmflg, size);
+ } else if ((id = findkey (key)) == -1) {
if (!(shmflg & IPC_CREAT))
- return -ENOENT;
- return newseg(key, shmflg, size);
+ err = -ENOENT;
+ else
+ err = newseg(key, shmflg, size);
+ } else if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL)) {
+ err = -EEXIST;
+ } else {
+ shp = shm_segs[id];
+ if (shp->shm_perm.mode & SHM_DEST)
+ err = -EIDRM;
+ else if (size > shp->shm_segsz)
+ err = -EINVAL;
+ else if (ipcperms (&shp->shm_perm, shmflg))
+ err = -EACCES;
+ else
+ err = (int) shp->shm_perm.seq * SHMMNI + id;
}
- if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL))
- return -EEXIST;
- shp = shm_segs[id];
- if (shp->shm_perm.mode & SHM_DEST)
- return -EIDRM;
- if (size > shp->shm_segsz)
- return -EINVAL;
- if (ipcperms (&shp->shm_perm, shmflg))
- return -EACCES;
- return (unsigned int) shp->shm_perm.seq * SHMMNI + id;
+ unlock_kernel();
+ return err;
}
/*
@@ -180,7 +189,7 @@ static void killseg (int id)
numpages = shp->shm_npages;
for (i = 0; i < numpages ; i++) {
pte_t pte;
- pte_val(pte) = shp->shm_pages[i];
+ pte = __pte(shp->shm_pages[i]);
if (pte_none(pte))
continue;
if (pte_present(pte)) {
@@ -202,16 +211,18 @@ asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
struct shmid_ds tbuf;
struct shmid_ds *shp;
struct ipc_perm *ipcp;
- int id, err;
+ int id, err = -EINVAL;
+ lock_kernel();
if (cmd < 0 || shmid < 0)
- return -EINVAL;
+ goto out;
if (cmd == IPC_SET) {
+ err = -EFAULT;
if (!buf)
- return -EFAULT;
+ goto out;
err = verify_area (VERIFY_READ, buf, sizeof (*buf));
if (err)
- return err;
+ goto out;
copy_from_user (&tbuf, buf, sizeof (*buf));
}
@@ -219,8 +230,9 @@ asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
case IPC_INFO:
{
struct shminfo shminfo;
+ err = -EFAULT;
if (!buf)
- return -EFAULT;
+ goto out;
shminfo.shmmni = SHMMNI;
shminfo.shmmax = SHMMAX;
shminfo.shmmin = SHMMIN;
@@ -228,18 +240,20 @@ asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
shminfo.shmseg = SHMSEG;
err = verify_area (VERIFY_WRITE, buf, sizeof (struct shminfo));
if (err)
- return err;
+ goto out;
copy_to_user (buf, &shminfo, sizeof(struct shminfo));
- return max_shmid;
+ err = max_shmid;
+ goto out;
}
case SHM_INFO:
{
struct shm_info shm_info;
+ err = -EFAULT;
if (!buf)
- return -EFAULT;
+ goto out;
err = verify_area (VERIFY_WRITE, buf, sizeof (shm_info));
if (err)
- return err;
+ goto out;
shm_info.used_ids = used_segs;
shm_info.shm_rss = shm_rss;
shm_info.shm_tot = shm_tot;
@@ -247,21 +261,24 @@ asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
shm_info.swap_attempts = swap_attempts;
shm_info.swap_successes = swap_successes;
copy_to_user (buf, &shm_info, sizeof(shm_info));
- return max_shmid;
+ err = max_shmid;
+ goto out;
}
case SHM_STAT:
+ err = -EFAULT;
if (!buf)
- return -EFAULT;
+ goto out;
err = verify_area (VERIFY_WRITE, buf, sizeof (*buf));
if (err)
- return err;
+ goto out;
+ err = -EINVAL;
if (shmid > max_shmid)
- return -EINVAL;
+ goto out;
shp = shm_segs[shmid];
if (shp == IPC_UNUSED || shp == IPC_NOID)
- return -EINVAL;
+ goto out;
if (ipcperms (&shp->shm_perm, S_IRUGO))
- return -EACCES;
+ goto out;
id = (unsigned int) shp->shm_perm.seq * SHMMNI + shmid;
tbuf.shm_perm = shp->shm_perm;
tbuf.shm_segsz = shp->shm_segsz;
@@ -272,42 +289,51 @@ asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
tbuf.shm_lpid = shp->shm_lpid;
tbuf.shm_nattch = shp->shm_nattch;
copy_to_user (buf, &tbuf, sizeof(*buf));
- return id;
+ err = id;
+ goto out;
}
shp = shm_segs[id = (unsigned int) shmid % SHMMNI];
+ err = -EINVAL;
if (shp == IPC_UNUSED || shp == IPC_NOID)
- return -EINVAL;
+ goto out;
+ err = -EIDRM;
if (shp->shm_perm.seq != (unsigned int) shmid / SHMMNI)
- return -EIDRM;
+ goto out;
ipcp = &shp->shm_perm;
switch (cmd) {
case SHM_UNLOCK:
+ err = -EPERM;
if (!suser())
- return -EPERM;
+ goto out;
+ err = -EINVAL;
if (!(ipcp->mode & SHM_LOCKED))
- return -EINVAL;
+ goto out;
ipcp->mode &= ~SHM_LOCKED;
break;
case SHM_LOCK:
/* Allow superuser to lock segment in memory */
/* Should the pages be faulted in here or leave it to user? */
/* need to determine interaction with current->swappable */
+ err = -EPERM;
if (!suser())
- return -EPERM;
+ goto out;
+ err = -EINVAL;
if (ipcp->mode & SHM_LOCKED)
- return -EINVAL;
+ goto out;
ipcp->mode |= SHM_LOCKED;
break;
case IPC_STAT:
+ err = -EACCES;
if (ipcperms (ipcp, S_IRUGO))
- return -EACCES;
+ goto out;
+ err = -EFAULT;
if (!buf)
- return -EFAULT;
+ goto out;
err = verify_area (VERIFY_WRITE, buf, sizeof (*buf));
if (err)
- return err;
+ goto out;
tbuf.shm_perm = shp->shm_perm;
tbuf.shm_segsz = shp->shm_segsz;
tbuf.shm_atime = shp->shm_atime;
@@ -328,7 +354,8 @@ asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
shp->shm_ctime = CURRENT_TIME;
break;
}
- return -EPERM;
+ err = -EPERM;
+ goto out;
case IPC_RMID:
if (suser() || current->euid == shp->shm_perm.uid ||
current->euid == shp->shm_perm.cuid) {
@@ -337,11 +364,16 @@ asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
killseg (id);
break;
}
- return -EPERM;
+ err = -EPERM;
+ goto out;
default:
- return -EINVAL;
+ err = -EINVAL;
+ goto out;
}
- return 0;
+ err = 0;
+out:
+ unlock_kernel();
+ return err;
}
/*
@@ -465,39 +497,42 @@ asmlinkage int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
{
struct shmid_ds *shp;
struct vm_area_struct *shmd;
- int err;
+ int err = -EINVAL;
unsigned int id;
unsigned long addr;
unsigned long len;
+ lock_kernel();
if (shmid < 0) {
/* printk("shmat() -> EINVAL because shmid = %d < 0\n",shmid); */
- return -EINVAL;
+ goto out;
}
shp = shm_segs[id = (unsigned int) shmid % SHMMNI];
if (shp == IPC_UNUSED || shp == IPC_NOID) {
/* printk("shmat() -> EINVAL because shmid = %d is invalid\n",shmid); */
- return -EINVAL;
+ goto out;
}
if (!(addr = (ulong) shmaddr)) {
if (shmflg & SHM_REMAP)
- return -EINVAL;
+ goto out;
+ err = -ENOMEM;
if (!(addr = get_unmapped_area(0, shp->shm_segsz)))
- return -ENOMEM;
+ goto out;
} else if (addr & (SHMLBA-1)) {
if (shmflg & SHM_RND)
addr &= ~(SHMLBA-1); /* round down */
else
- return -EINVAL;
+ goto out;
}
/*
* Check if addr exceeds TASK_SIZE (from do_mmap)
*/
len = PAGE_SIZE*shp->shm_npages;
- if (addr >= TASK_SIZE || len > TASK_SIZE || addr > TASK_SIZE - len)
- return -EINVAL;
+ err = -EINVAL;
+ if (addr >= TASK_SIZE || len > TASK_SIZE || addr > TASK_SIZE - len)
+ goto out;
/*
* If shm segment goes below stack, make sure there is some
* space left for the stack to grow (presently 4 pages).
@@ -506,26 +541,30 @@ asmlinkage int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
addr > current->mm->start_stack - PAGE_SIZE*(shp->shm_npages + 4))
{
/* printk("shmat() -> EINVAL because segment intersects stack\n"); */
- return -EINVAL;
+ goto out;
}
if (!(shmflg & SHM_REMAP))
if ((shmd = find_vma_intersection(current->mm, addr, addr + shp->shm_segsz))) {
/* printk("shmat() -> EINVAL because the interval [0x%lx,0x%lx) intersects an already mapped interval [0x%lx,0x%lx).\n",
addr, addr + shp->shm_segsz, shmd->vm_start, shmd->vm_end); */
- return -EINVAL;
+ goto out;
}
+ err = -EACCES;
if (ipcperms(&shp->shm_perm, shmflg & SHM_RDONLY ? S_IRUGO : S_IRUGO|S_IWUGO))
- return -EACCES;
+ goto out;
+ err = -EIDRM;
if (shp->shm_perm.seq != (unsigned int) shmid / SHMMNI)
- return -EIDRM;
+ goto out;
- shmd = (struct vm_area_struct *) kmalloc (sizeof(*shmd), GFP_KERNEL);
+ err = -ENOMEM;
+ shmd = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
if (!shmd)
- return -ENOMEM;
+ goto out;
if ((shp != shm_segs[id]) || (shp->shm_perm.seq != (unsigned int) shmid / SHMMNI)) {
- kfree(shmd);
- return -EIDRM;
+ kmem_cache_free(vm_area_cachep, shmd);
+ err = -EIDRM;
+ goto out;
}
shmd->vm_pte = SWP_ENTRY(SHM_SWP_TYPE, id);
@@ -545,8 +584,8 @@ asmlinkage int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
if ((err = shm_map (shmd))) {
if (--shp->shm_nattch <= 0 && shp->shm_perm.mode & SHM_DEST)
killseg(id);
- kfree(shmd);
- return err;
+ kmem_cache_free(vm_area_cachep, shmd);
+ goto out;
}
insert_attach(shp,shmd); /* insert shmd into shp->attaches */
@@ -555,7 +594,10 @@ asmlinkage int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
shp->shm_atime = CURRENT_TIME;
*raddr = addr;
- return 0;
+ err = 0;
+out:
+ unlock_kernel();
+ return err;
}
/* This is called by fork, once for every shm attach. */
@@ -649,21 +691,21 @@ static pte_t shm_swap_in(struct vm_area_struct * shmd, unsigned long offset, uns
return BAD_PAGE;
}
- pte_val(pte) = shp->shm_pages[idx];
+ pte = __pte(shp->shm_pages[idx]);
if (!pte_present(pte)) {
unsigned long page = get_free_page(GFP_KERNEL);
if (!page) {
oom(current);
return BAD_PAGE;
}
- pte_val(pte) = shp->shm_pages[idx];
+ pte = __pte(shp->shm_pages[idx]);
if (pte_present(pte)) {
free_page (page); /* doesn't sleep */
goto done;
}
if (!pte_none(pte)) {
read_swap_page(pte_val(pte), (char *) page);
- pte_val(pte) = shp->shm_pages[idx];
+ pte = __pte(shp->shm_pages[idx]);
if (pte_present(pte)) {
free_page (page); /* doesn't sleep */
goto done;
@@ -679,7 +721,7 @@ static pte_t shm_swap_in(struct vm_area_struct * shmd, unsigned long offset, uns
done: /* pte_val(pte) == shp->shm_pages[idx] */
current->min_flt++;
- mem_map[MAP_NR(pte_page(pte))].count++;
+ atomic_inc(&mem_map[MAP_NR(pte_page(pte))].count);
return pte_modify(pte, shmd->vm_page_prot);
}
@@ -723,7 +765,7 @@ int shm_swap (int prio, int dma)
if (idx >= shp->shm_npages)
goto next_id;
- pte_val(page) = shp->shm_pages[idx];
+ page = __pte(shp->shm_pages[idx]);
if (!pte_present(page))
goto check_table;
if (dma && !PageDMA(&mem_map[MAP_NR(pte_page(page))]))
@@ -774,11 +816,12 @@ int shm_swap (int prio, int dma)
continue;
}
if (pte_page(pte) != pte_page(page))
- printk("shm_swap_out: page and pte mismatch\n");
+ printk("shm_swap_out: page and pte mismatch %lx %lx\n",
+ pte_page(pte),pte_page(page));
flush_cache_page(shmd, tmp);
set_pte(page_table,
__pte(shmd->vm_pte + SWP_ENTRY(0, idx << SHM_IDX_SHIFT)));
- mem_map[MAP_NR(pte_page(pte))].count--;
+ atomic_dec(&mem_map[MAP_NR(pte_page(pte))].count);
if (shmd->vm_mm->rss > 0)
shmd->vm_mm->rss--;
flush_tlb_page(shmd, tmp);
@@ -788,7 +831,7 @@ int shm_swap (int prio, int dma)
break;
}
- if (mem_map[MAP_NR(pte_page(page))].count != 1)
+ if (atomic_read(&mem_map[MAP_NR(pte_page(page))].count) != 1)
goto check_table;
shp->shm_pages[idx] = swap_nr;
write_swap_page (swap_nr, (char *) pte_page(page));