patch-1.3.100 linux/ipc/msg.c
Next file: linux/net/ipv4/arp.c
Previous file: linux/init/main.c
Back to the patch index
Back to the overall index
- Lines: 368
- Date:
Wed May 8 10:32:41 1996
- Orig file:
v1.3.99/linux/ipc/msg.c
- Orig date:
Tue May 7 16:22:40 1996
diff -u --recursive --new-file v1.3.99/linux/ipc/msg.c linux/ipc/msg.c
@@ -2,8 +2,9 @@
* linux/ipc/msg.c
* Copyright (C) 1992 Krishna Balasubramanian
*
- * Kerneld extensions by Bjorn Ekwall <bj0rn@blox.se> in May 1995
+ * 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>
@@ -46,6 +47,39 @@
return;
}
+/*
+ * If the send queue is full, try to free any old messages.
+ * These are most probably unwanted, since noone 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;
@@ -53,6 +87,7 @@
struct ipc_perm *ipcp;
struct msg *msgh;
long mtype;
+ unsigned long flags;
if (msgsz > MSGMAX || (long) msgsz < 0 || msqid < 0)
return -EINVAL;
@@ -81,7 +116,7 @@
if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI)
return -EIDRM;
/*
- * Non-root processes may send to kerneld!
+ * 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...
*/
@@ -90,23 +125,26 @@
return -EACCES;
if (msgsz + msq->msg_cbytes > msq->msg_qbytes) {
- /* no space in queue */
- if (msgflg & IPC_NOWAIT)
- return -EAGAIN;
- if (current->signal & ~current->blocked)
- return -EINTR;
- if (intr_count) {
- /* Very unlikely, but better safe than sorry... */
- printk("Ouch, kerneld:msgsnd wants to sleep at interrupt!\n");
- return -EINTR;
+ 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 (current->signal & ~current->blocked)
+ return -EINTR;
+ if (intr_count) {
+ /* 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;
}
- interruptible_sleep_on (&msq->wwait);
- goto slept;
}
/* allocate message header and text space*/
- msgh = (struct msg *) kmalloc (sizeof(*msgh) + msgsz,
- (intr_count ? GFP_ATOMIC : GFP_USER));
+ msgh = (struct msg *) kmalloc (sizeof(*msgh) + msgsz, GFP_ATOMIC);
if (!msgh)
return -ENOMEM;
msgh->msg_spot = (char *) (msgh + 1);
@@ -122,9 +160,8 @@
* Note that the kernel supplies a pointer
* but the user-level kerneld uses a char array...
*/
- memcpy(msgh->msg_spot, (char *)(&(kdmp->id)), sizeof(long));
- memcpy(msgh->msg_spot + sizeof(long), kdmp->text,
- msgsz - sizeof(long));
+ memcpy(msgh->msg_spot, (char *)(&(kdmp->id)), KDHDR);
+ memcpy(msgh->msg_spot + KDHDR, kdmp->text, msgsz - KDHDR);
}
else
memcpy_fromfs (msgh->msg_spot, msgp->mtext, msgsz);
@@ -136,20 +173,25 @@
}
msgh->msg_next = NULL;
+ msgh->msg_ts = msgsz;
+ msgh->msg_type = mtype;
+ msgh->msg_stime = CURRENT_TIME;
+
+ save_flags(flags);
+ cli();
if (!msq->msg_first)
msq->msg_first = msq->msg_last = msgh;
else {
msq->msg_last->msg_next = msgh;
msq->msg_last = msgh;
}
- msgh->msg_ts = msgsz;
- msgh->msg_type = mtype;
msq->msg_cbytes += msgsz;
msgbytes += msgsz;
msghdrs++;
msq->msg_qnum++;
msq->msg_lspid = current->pid;
msq->msg_stime = CURRENT_TIME;
+ restore_flags(flags);
if (msq->rwait)
wake_up (&msq->rwait);
return 0;
@@ -166,20 +208,24 @@
{
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, -ENODEV, "" };
+ struct kerneld_msg kmsp = { msgid, NULL_KDHDR, "" };
- printk(KERN_ALERT "Ouch, kerneld timed out, message failed\n");
- real_msgsnd(kerneld_msqid, (struct msgbuf *)&kmsp,
- sizeof(long),
+ 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);
}
}
@@ -192,6 +238,7 @@
struct msg *tmsg, *leastp = NULL;
struct msg *nmsg = NULL;
int id, err;
+ unsigned long flags;
if (msqid < 0 || (long) msgsz < 0)
return -EINVAL;
@@ -236,15 +283,18 @@
}
if ((msgflg & IPC_KERNELD) == 0) {
/*
- * Non-root processes may receive from kerneld!
+ * 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;
+ DROP_TIMER; /* Not needed, but doesn't hurt */
return -EACCES;
}
}
+
+ save_flags(flags);
+ cli();
if (msgtyp == 0)
nmsg = msq->msg_first;
else if (msgtyp > 0) {
@@ -269,14 +319,16 @@
if (leastp && leastp->msg_type <= - msgtyp)
nmsg = leastp;
}
+ restore_flags(flags);
if (nmsg) { /* done finding a message */
DROP_TIMER;
if ((msgsz < nmsg->msg_ts) && !(msgflg & MSG_NOERROR)) {
- DROP_TIMER;
return -E2BIG;
}
msgsz = (msgsz > nmsg->msg_ts)? nmsg->msg_ts : msgsz;
+ save_flags(flags);
+ cli();
if (nmsg == msq->msg_first)
msq->msg_first = nmsg->msg_next;
else {
@@ -296,6 +348,7 @@
msgbytes -= nmsg->msg_ts;
msghdrs--;
msq->msg_cbytes -= nmsg->msg_ts;
+ restore_flags(flags);
if (msq->wwait)
wake_up (&msq->wwait);
/*
@@ -306,23 +359,21 @@
struct kerneld_msg *kdmp = (struct kerneld_msg *) msgp;
memcpy((char *)(&(kdmp->id)),
- nmsg->msg_spot,
- sizeof(long));
+ nmsg->msg_spot, KDHDR);
/*
* Note that kdmp->text is a pointer
* when called from kernel space!
*/
- if ((msgsz > sizeof(long)) && kdmp->text)
+ if ((msgsz > KDHDR) && kdmp->text)
memcpy(kdmp->text,
- nmsg->msg_spot + sizeof(long),
- msgsz - sizeof(long));
+ nmsg->msg_spot + KDHDR,
+ msgsz - KDHDR);
}
else {
put_user (nmsg->msg_type, &msgp->mtype);
memcpy_tofs (msgp->mtext, nmsg->msg_spot, msgsz);
}
kfree(nmsg);
- DROP_TIMER;
return msgsz;
} else { /* did not find a message */
if (msgflg & IPC_NOWAIT) {
@@ -333,12 +384,6 @@
DROP_TIMER;
return -EINTR;
}
- if (intr_count) {
- DROP_TIMER;
- /* Won't happen... */
- printk("Ouch, kerneld:msgrcv wants to sleep at interrupt!\n");
- return -EINTR;
- }
interruptible_sleep_on (&msq->rwait);
}
} /* end while */
@@ -348,14 +393,14 @@
asmlinkage int sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg)
{
- /* IPC_KERNELD is used as a marker for kernel calls */
+ /* IPC_KERNELD is used as a marker for kernel level calls */
return real_msgsnd(msqid, msgp, msgsz, msgflg & ~IPC_KERNELD);
}
asmlinkage int sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz,
long msgtyp, int msgflg)
{
- /* IPC_KERNELD is used as a marker for kernel calls */
+ /* IPC_KERNELD is used as a marker for kernel level calls */
return real_msgrcv (msqid, msgp, msgsz, msgtyp, msgflg & ~IPC_KERNELD);
}
@@ -431,6 +476,12 @@
int i;
if (!suser())
return -EPERM;
+#ifdef NEW_KERNELD_PROTOCOL
+ if ((msgflg & IPC_KERNELD) == OLDIPC_KERNELD) {
+ printk(KERN_ALERT "Please recompile your kerneld daemons!\n");
+ return -EPERM;
+ }
+#endif
if ((kerneld_msqid == -1) && (kerneld_msqid =
newque(IPC_PRIVATE, msgflg & S_IRWXU)) < 0)
return -ENOSPC;
@@ -648,10 +699,10 @@
* 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 long, followed by a char array.
- * The long is used to hold the sequence number of the request, which will
+ * 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 long will be used to store the exit status
+ * 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.
@@ -666,7 +717,7 @@
* 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 long that is always sent first in a kerneld message
+ * 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.
@@ -680,8 +731,9 @@
int status = -ENOSYS;
#ifdef CONFIG_KERNELD
static int id = KERNELD_MINSEQ;
- struct kerneld_msg kmsp = { msgtype, 0, (char *)text };
+ 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;
@@ -689,12 +741,19 @@
/* Do not wait for an answer at interrupt-time! */
if (intr_count)
ret_size &= ~KERNELD_WAIT;
+#ifdef NEW_KERNELD_PROTOCOL
+ else
+ kmsp.pid = current->pid;
+#endif
- msgsz += sizeof(long);
+ msgsz += KDHDR;
if (ret_size & KERNELD_WAIT) {
- if (++id <= 0)
+ 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);
@@ -702,7 +761,7 @@
ret_size &= ~KERNELD_WAIT;
kmsp.text = (char *)ret_val;
status = real_msgrcv(kerneld_msqid, (struct msgbuf *)&kmsp,
- sizeof(long) + ((ret_val)?ret_size:0),
+ KDHDR + ((ret_val)?ret_size:0),
kmsp.id, msgflg);
if (status > 0) /* a valid answer contains at least a long */
status = kmsp.id;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this