diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1997-04-29 21:13:14 +0000 |
---|---|---|
committer | <ralf@linux-mips.org> | 1997-04-29 21:13:14 +0000 |
commit | 19c9bba94152148523ba0f7ef7cffe3d45656b11 (patch) | |
tree | 40b1cb534496a7f1ca0f5c314a523c69f1fee464 /ipc | |
parent | 7206675c40394c78a90e74812bbdbf8cf3cca1be (diff) |
Import of Linux/MIPS 2.1.36
Diffstat (limited to 'ipc')
-rw-r--r-- | ipc/msg.c | 133 | ||||
-rw-r--r-- | ipc/sem.c | 187 | ||||
-rw-r--r-- | ipc/shm.c | 195 |
3 files changed, 322 insertions, 193 deletions
@@ -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 @@ -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; } /* @@ -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)); |