summaryrefslogtreecommitdiffstats
path: root/ipc/msg.c
diff options
context:
space:
mode:
Diffstat (limited to 'ipc/msg.c')
-rw-r--r--ipc/msg.c341
1 files changed, 21 insertions, 320 deletions
diff --git a/ipc/msg.c b/ipc/msg.c
index 6ff658b02..30fe31239 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -1,19 +1,13 @@
/*
* linux/ipc/msg.c
* Copyright (C) 1992 Krishna Balasubramanian
- *
- * Kerneld extensions by Bjorn Ekwall <bj0rn@blox.se> in May 1995, and May 1996
- *
- * See <linux/kerneld.h> for the (optional) new kerneld protocol
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/msg.h>
#include <linux/stat.h>
#include <linux/malloc.h>
-#include <linux/kerneld.h>
#include <linux/interrupt.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
@@ -34,11 +28,6 @@ static unsigned short msg_seq = 0;
static int used_queues = 0;
static int max_msqid = 0;
static struct wait_queue *msg_lock = NULL;
-static int kerneld_msqid = -1;
-
-#define MAX_KERNELDS 20
-static int kerneld_arr[MAX_KERNELDS];
-static int n_kernelds = 0;
__initfunc(void msg_init (void))
{
@@ -51,39 +40,6 @@ __initfunc(void msg_init (void))
return;
}
-/*
- * If the send queue is full, try to free any old messages.
- * These are most probably unwanted, since no one has picked them up...
- */
-#define MSG_FLUSH_TIME 10 /* seconds */
-static void flush_msg(struct msqid_ds *msq)
-{
- struct msg *nmsg;
- unsigned long flags;
- int flushed = 0;
-
- save_flags(flags);
- cli();
-
- /* messages were put on the queue in time order */
- while ( (nmsg = msq->msg_first) &&
- ((CURRENT_TIME - nmsg->msg_stime) > MSG_FLUSH_TIME)) {
- msgbytes -= nmsg->msg_ts;
- msghdrs--;
- msq->msg_cbytes -= nmsg->msg_ts;
- msq->msg_qnum--;
- msq->msg_first = nmsg->msg_next;
- ++flushed;
- kfree(nmsg);
- }
-
- if (msq->msg_qnum == 0)
- msq->msg_first = msq->msg_last = NULL;
- restore_flags(flags);
- if (flushed)
- printk(KERN_WARNING "flushed %d old SYSVIPC messages", flushed);
-}
-
static int real_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg)
{
int id, err;
@@ -97,20 +53,12 @@ static int real_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg
return -EINVAL;
if (!msgp)
return -EFAULT;
- /*
- * Calls from kernel level (IPC_KERNELD set)
- * have the message somewhere in kernel space already!
- */
- if ((msgflg & IPC_KERNELD))
- mtype = msgp->mtype;
- else {
- err = verify_area (VERIFY_READ, msgp->mtext, msgsz);
- if (err)
- return err;
- get_user(mtype, &msgp->mtype);
- if (mtype < 1)
- return -EINVAL;
- }
+ err = verify_area (VERIFY_READ, msgp->mtext, msgsz);
+ if (err)
+ return err;
+ get_user(mtype, &msgp->mtype);
+ if (mtype < 1)
+ return -EINVAL;
id = (unsigned int) msqid % MSGMNI;
msq = msgque [id];
if (msq == IPC_UNUSED || msq == IPC_NOID)
@@ -120,29 +68,17 @@ static int real_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg
slept:
if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI)
return -EIDRM;
- /*
- * Non-root kernel level processes may send to kerneld!
- * i.e. no permission check if called from the kernel
- * otoh we don't want user level non-root snoopers...
- */
- if ((msgflg & IPC_KERNELD) == 0)
- if (ipcperms(ipcp, S_IWUGO))
- return -EACCES;
+
+ if (ipcperms(ipcp, S_IWUGO))
+ return -EACCES;
if (msgsz + msq->msg_cbytes > msq->msg_qbytes) {
- if ((kerneld_msqid != -1) && (kerneld_msqid == msqid))
- flush_msg(msq); /* flush the kerneld channel only */
if (msgsz + msq->msg_cbytes > msq->msg_qbytes) {
/* still no space in queue */
if (msgflg & IPC_NOWAIT)
return -EAGAIN;
if (signal_pending(current))
return -EINTR;
- if (in_interrupt()) {
- /* Very unlikely, but better safe than sorry */
- printk(KERN_WARNING "Ouch, kerneld:msgsnd buffers full!\n");
- return -EINTR;
- }
interruptible_sleep_on (&msq->wwait);
goto slept;
}
@@ -154,22 +90,7 @@ static int real_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg
return -ENOMEM;
msgh->msg_spot = (char *) (msgh + 1);
- /*
- * Calls from kernel level (IPC_KERNELD set)
- * have the message somewhere in kernel space already!
- */
- if (msgflg & IPC_KERNELD) {
- struct kerneld_msg *kdmp = (struct kerneld_msg *)msgp;
-
- /*
- * Note that the kernel supplies a pointer
- * but the user-level kerneld uses a char array...
- */
- memcpy(msgh->msg_spot, (char *)(&(kdmp->id)), KDHDR);
- memcpy(msgh->msg_spot + KDHDR, kdmp->text, msgsz - KDHDR);
- }
- else
- copy_from_user (msgh->msg_spot, msgp->mtext, msgsz);
+ copy_from_user (msgh->msg_spot, msgp->mtext, msgsz);
if (msgque[id] == IPC_UNUSED || msgque[id] == IPC_NOID
|| msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) {
@@ -201,42 +122,8 @@ static int real_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg
return 0;
}
-/*
- * Take care of missing kerneld, especially in case of multiple daemons
- */
-#define KERNELD_TIMEOUT 1 * (HZ)
-#define DROP_TIMER del_timer(&kd_timer)
-/*#define DROP_TIMER if ((msgflg & IPC_KERNELD) && kd_timer.next && kd_timer.prev) del_timer(&kd_timer)*/
-
-static void kd_timeout(unsigned long msgid)
-{
- struct msqid_ds *msq;
- struct msg *tmsg;
- unsigned long flags;
-
- msq = msgque [ (unsigned int) kerneld_msqid % MSGMNI ];
- if (msq == IPC_NOID || msq == IPC_UNUSED)
- return;
-
- save_flags(flags);
- cli();
- for (tmsg = msq->msg_first; tmsg; tmsg = tmsg->msg_next)
- if (*(long *)(tmsg->msg_spot) == msgid)
- break;
- restore_flags(flags);
- if (tmsg) { /* still there! */
- struct kerneld_msg kmsp = { msgid, NULL_KDHDR, "" };
-
- printk(KERN_ALERT "Ouch, no kerneld for message %ld\n", msgid);
- kmsp.id = -ENODEV;
- real_msgsnd(kerneld_msqid, (struct msgbuf *)&kmsp, KDHDR,
- S_IRUSR | S_IWUSR | IPC_KERNELD | MSG_NOERROR);
- }
-}
-
static int real_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, int msgflg)
{
- struct timer_list kd_timer = { NULL, NULL, 0, 0, 0};
struct msqid_ds *msq;
struct ipc_perm *ipcp;
struct msg *tmsg, *leastp = NULL;
@@ -248,15 +135,10 @@ static int real_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgty
return -EINVAL;
if (!msgp || !msgp->mtext)
return -EFAULT;
- /*
- * Calls from kernel level (IPC_KERNELD set)
- * wants the message put in kernel space!
- */
- if ((msgflg & IPC_KERNELD) == 0) {
- err = verify_area (VERIFY_WRITE, msgp->mtext, msgsz);
- if (err)
- return err;
- }
+
+ err = verify_area (VERIFY_WRITE, msgp->mtext, msgsz);
+ if (err)
+ return err;
id = (unsigned int) msqid % MSGMNI;
msq = msgque [id];
@@ -264,16 +146,6 @@ static int real_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgty
return -EINVAL;
ipcp = &msq->msg_perm;
- /*
- * Start timer for missing kerneld
- */
- if (msgflg & IPC_KERNELD) {
- kd_timer.data = (unsigned long)msgtyp;
- kd_timer.expires = jiffies + KERNELD_TIMEOUT;
- kd_timer.function = kd_timeout;
- add_timer(&kd_timer);
- }
-
/*
* find message of correct type.
* msgtyp = 0 => get first.
@@ -282,19 +154,10 @@ static int real_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgty
*/
while (!nmsg) {
if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) {
- DROP_TIMER;
return -EIDRM;
}
- if ((msgflg & IPC_KERNELD) == 0) {
- /*
- * All kernel level processes may receive from kerneld!
- * i.e. no permission check if called from the kernel
- * otoh we don't want user level non-root snoopers...
- */
- if (ipcperms (ipcp, S_IRUGO)) {
- DROP_TIMER; /* Not needed, but doesn't hurt */
- return -EACCES;
- }
+ if (ipcperms (ipcp, S_IRUGO)) {
+ return -EACCES;
}
save_flags(flags);
@@ -326,7 +189,6 @@ static int real_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgty
restore_flags(flags);
if (nmsg) { /* done finding a message */
- DROP_TIMER;
if ((msgsz < nmsg->msg_ts) && !(msgflg & MSG_NOERROR)) {
return -E2BIG;
}
@@ -354,43 +216,20 @@ static int real_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgty
msq->msg_cbytes -= nmsg->msg_ts;
restore_flags(flags);
wake_up (&msq->wwait);
- /*
- * Calls from kernel level (IPC_KERNELD set)
- * wants the message copied to kernel space!
- */
- if (msgflg & IPC_KERNELD) {
- struct kerneld_msg *kdmp = (struct kerneld_msg *) msgp;
-
- memcpy((char *)(&(kdmp->id)),
- nmsg->msg_spot, KDHDR);
- /*
- * Note that kdmp->text is a pointer
- * when called from kernel space!
- */
- if ((msgsz > KDHDR) && kdmp->text)
- memcpy(kdmp->text,
- nmsg->msg_spot + KDHDR,
- msgsz - KDHDR);
- }
- else {
- put_user (nmsg->msg_type, &msgp->mtype);
- copy_to_user (msgp->mtext, nmsg->msg_spot, msgsz);
- }
+ put_user (nmsg->msg_type, &msgp->mtype);
+ copy_to_user (msgp->mtext, nmsg->msg_spot, msgsz);
kfree(nmsg);
return msgsz;
} else { /* did not find a message */
if (msgflg & IPC_NOWAIT) {
- DROP_TIMER;
return -ENOMSG;
}
if (signal_pending(current)) {
- DROP_TIMER;
return -EINTR;
}
interruptible_sleep_on (&msq->rwait);
}
} /* end while */
- DROP_TIMER;
return -1;
}
@@ -398,9 +237,8 @@ asmlinkage int sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msg
{
int ret;
- /* IPC_KERNELD is used as a marker for kernel level calls */
lock_kernel();
- ret = real_msgsnd(msqid, msgp, msgsz, msgflg & ~IPC_KERNELD);
+ ret = real_msgsnd(msqid, msgp, msgsz, msgflg);
unlock_kernel();
return ret;
}
@@ -410,9 +248,8 @@ asmlinkage int sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz,
{
int ret;
- /* IPC_KERNELD is used as a marker for kernel level calls */
lock_kernel();
- ret = real_msgrcv (msqid, msgp, msgsz, msgtyp, msgflg & ~IPC_KERNELD);
+ ret = real_msgrcv (msqid, msgp, msgsz, msgtyp, msgflg);
unlock_kernel();
return ret;
}
@@ -479,36 +316,7 @@ asmlinkage int sys_msgget (key_t key, int msgflg)
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())
- goto out;
-#ifdef NEW_KERNELD_PROTOCOL
- if ((msgflg & IPC_KERNELD) == OLDIPC_KERNELD) {
- printk(KERN_ALERT "Please recompile your kerneld daemons!\n");
- goto out;
- }
-#endif
- ret = -ENOSPC;
- if ((kerneld_msqid == -1) && (kerneld_msqid =
- newque(IPC_PRIVATE, msgflg & S_IRWXU)) < 0)
- goto out;
- for (i = 0; i < MAX_KERNELDS; ++i) {
- if (kerneld_arr[i] == 0) {
- kerneld_arr[i] = current->pid;
- ++n_kernelds;
- ret = kerneld_msqid;
- goto out;
- }
- }
- goto out;
- }
- /* else it is a "normal" request */
if (key == IPC_PRIVATE)
ret = newque(key, msgflg);
else if ((id = findkey (key)) == -1) { /* key not used */
@@ -527,7 +335,6 @@ asmlinkage int sys_msgget (key_t key, int msgflg)
else
ret = (unsigned int) msq->msg_perm.seq * MSGMNI + id;
}
-out:
unlock_kernel();
return ret;
}
@@ -687,12 +494,7 @@ asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf)
if (current->euid != ipcp->cuid &&
current->euid != ipcp->uid && !suser())
goto out;
- /*
- * There is only one kerneld message queue,
- * mark it as non-existent
- */
- if ((kerneld_msqid >= 0) && (msqid == kerneld_msqid))
- kerneld_msqid = -1;
+
freeque (id);
err = 0;
goto out;
@@ -705,104 +507,3 @@ out:
return err;
}
-/*
- * We do perhaps need a "flush" for waiting processes,
- * so that if they are terminated, a call from do_exit
- * will minimize the possibility of orphaned received
- * messages in the queue. For now we just make sure
- * that the queue is shut down whenever all kernelds have died.
- */
-void kerneld_exit(void)
-{
- int i;
-
- if (kerneld_msqid == -1)
- return;
- for (i = 0; i < MAX_KERNELDS; ++i) {
- if (kerneld_arr[i] == current->pid) {
- kerneld_arr[i] = 0;
- --n_kernelds;
- if (n_kernelds == 0)
- sys_msgctl(kerneld_msqid, IPC_RMID, NULL);
- break;
- }
- }
-}
-
-/*
- * Kerneld internal message format/syntax:
- *
- * The message type from the kernel to kerneld is used to specify _what_
- * function we want kerneld to perform.
- *
- * The "normal" message area is divided into a header, followed by a char array.
- * The header is used to hold the sequence number of the request, which will
- * be used as the return message type from kerneld back to the kernel.
- * In the return message, the header will be used to store the exit status
- * of the kerneld "job", or task.
- * The character array is used to pass parameters to kerneld and (optional)
- * return information from kerneld back to the kernel.
- * It is the responsibility of kerneld and the kernel level caller
- * to set usable sizes on the parameter/return value array, since
- * that information is _not_ included in the message format
- */
-
-/*
- * The basic kernel level entry point to kerneld.
- * msgtype should correspond to a task type for (a) kerneld
- * ret_size is the size of the (optional) return _value,
- * OR-ed with KERNELD_WAIT if we want an answer
- * msgsize is the size (in bytes) of the message, not including
- * the header that is always sent first in a kerneld message
- * text is the parameter for the kerneld specific task
- * ret_val is NULL or the kernel address where an expected answer
- * from kerneld should be placed.
- *
- * See <linux/kerneld.h> for usage (inline convenience functions)
- *
- */
-int kerneld_send(int msgtype, int ret_size, int msgsz,
- const char *text, const char *ret_val)
-{
- int status = -ENOSYS;
-#ifdef CONFIG_KERNELD
- static int id = KERNELD_MINSEQ;
- struct kerneld_msg kmsp = { msgtype, NULL_KDHDR, (char *)text };
- int msgflg = S_IRUSR | S_IWUSR | IPC_KERNELD | MSG_NOERROR;
- unsigned long flags;
-
- if (kerneld_msqid == -1)
- return -ENODEV;
-
- /* Do not wait for an answer at interrupt-time! */
- if (in_interrupt())
- ret_size &= ~KERNELD_WAIT;
-#ifdef NEW_KERNELD_PROTOCOL
- else
- kmsp.pid = current->pid;
-#endif
-
- msgsz += KDHDR;
- if (ret_size & KERNELD_WAIT) {
- save_flags(flags);
- cli();
- if (++id <= 0) /* overflow */
- id = KERNELD_MINSEQ;
- kmsp.id = id;
- restore_flags(flags);
- }
-
- status = real_msgsnd(kerneld_msqid, (struct msgbuf *)&kmsp, msgsz, msgflg);
- if ((status >= 0) && (ret_size & KERNELD_WAIT)) {
- ret_size &= ~KERNELD_WAIT;
- kmsp.text = (char *)ret_val;
- status = real_msgrcv(kerneld_msqid, (struct msgbuf *)&kmsp,
- KDHDR + ((ret_val)?ret_size:0),
- kmsp.id, msgflg);
- if (status > 0) /* a valid answer contains at least a long */
- status = kmsp.id;
- }
-
-#endif /* CONFIG_KERNELD */
- return status;
-}