removal of 4056 bytes msgsnd/msgrcv limit (patch)

Frodo Looijaard (peeter_joot@VNET.IBM.COM)
Sun, 6 Dec 1998 12:46:02 -0500 (EST)


Hello,

Appended below is patch to remove the 4056 byte ipc message limits, and the
64K message queue limits. These limits are made dynamic (adjustable via
proc/sysctl).

vmalloc is used for "large" messages (over MSGMAX). Since there were limiting
unsigned short fields in msgid_ds there is now a msqid_ds_kernel structure
where unsigned int is used instead. The fields that were formerly __wwait,
and __rwait in the user land msqid_ds structure are now used to return
the msg_cbytes, and msg_qbytes fields -- the old fields are also set for
backwards compatability, but they will be insufficient if >64K messages or
message queues are used.

As one can now potentially use a lot of unswappable kernel memory for messages
the total amount of such memory is now limited by a KERN_MSGPOOL sysctl.

I would appriciate anybody that is interested to try these out, and give me
any feedback. If possible I would like to see this change in 2.2 -- most
of the changes are quite simple (primarily search and replaces to accomodate
the split of the user/kernel msqid_ds structures). I know that at least db2
for linux would be able to use this -- however we would prefer not to have
to ship kernel patches with our distribution.

Also appended below is a replacement userland sys/msq_buf.h and a msgctl
function that hides the differences in whether the running kernel supports
large message queues or not. You can use this to patch ipcs so that it will
ipcs -q shows the correct info if using large message queues.

Peeter

--
Peeter Joot                                          peeterj@ca.ibm.com

--------------------------------------------------------------------------- kernel patch (2.1.131) ---------------------------------------------------------------------------

diff -ur linux-2.1.131.orig/Documentation/sysctl/kernel.txt linux-2.1.131.clean/Documentation/sysctl/kernel.txt --- linux-2.1.131.orig/Documentation/sysctl/kernel.txt Sun Dec 6 09:06:57 1998 +++ linux-2.1.131.clean/Documentation/sysctl/kernel.txt Sun Dec 6 09:03:10 1998 @@ -25,6 +25,9 @@ - java-appletviewer [ binfmt_java, obsolete ] - java-interpreter [ binfmt_java, obsolete ] - modprobe ==> Documentation/kmod.txt +- msgmax [ sysv ipc ] +- msgmnb [ sysv ipc ] +- msgpool [ sysv ipc ] - osrelease - ostype - panic @@ -33,6 +36,7 @@ - real-root-dev ==> Documentation/initrd.txt - reboot-cmd [ SPARC only ] - sg-big-buff [ generic SCSI device (sg) ] +- shmmax [ sysv ipc ] - version - zero-paged [ PPC only ]

@@ -89,6 +93,38 @@

==============================================================

+msgmax: + +This value can be used to query and set the run time limit +on the maximum message size that can be sent. This defaults +to MSGMAX, which despite it's small size (4056) seems to have +been sufficient for a long time. + +msgmax is now effectively limited by physical memory. Users +should note that indiscriminately increasing this limit is not +a good idea since queued messages are stored in non swappable +kernel space. Increasing this limit should be accompanied +with suitable modifications to msgmnb and msgpool. + +============================================================== + +msgmnb: + +This value can be used to query and set the default maximum +number of bytes in a message queue. Note that this can also +be set on a per queue basis via msgctl, but a root user is +required to do so. This value defaults to MSGMNB. + +============================================================== + +msgpool: + +This value can be used to query and set the maximum total +number of bytes in all message queues. This value defaults +to MSGPOOL*1024. + +============================================================== + osrelease, ostype & version:

# cat osrelease @@ -164,6 +200,15 @@ There shouldn't be any reason to change this value. If you can come up with one, you probably know what you are doing anyway :) + +============================================================== + +shmmax: + +This value can be used to query and set the run time limit +on the maximum shared memory segment size that can be created. +Shared memory segments up to 1Gb are now supported in the +kernel. This value defaults to SHMMAX.

==============================================================

diff -ur linux-2.1.131.orig/include/linux/msg.h linux-2.1.131.clean/include/linux/msg.h --- linux-2.1.131.orig/include/linux/msg.h Fri Jun 5 02:34:06 1998 +++ linux-2.1.131.clean/include/linux/msg.h Sun Dec 6 08:33:42 1998 @@ -12,22 +12,56 @@ #define MSG_EXCEPT 020000 /* recv any msg except of specified type.*/

/* one msqid structure for each queue on the system */ -struct msqid_ds { +struct msqid_ds_base { struct ipc_perm msg_perm; struct msg *msg_first; /* first message on queue */ struct msg *msg_last; /* last message in queue */ __kernel_time_t msg_stime; /* last msgsnd time */ __kernel_time_t msg_rtime; /* last msgrcv time */ __kernel_time_t msg_ctime; /* last change time */ +}; + +#ifdef __KERNEL__ + +struct msqid_ds_kernel { + struct msqid_ds_base u; struct wait_queue *wwait; struct wait_queue *rwait; - unsigned short msg_cbytes; /* current number of bytes on queue */ + unsigned int msg_cbytes; /* current number of bytes on queue */ + unsigned short msg_qnum; /* number of messages in queue */ + unsigned int msg_qbytes; /* max number of bytes on queue */ + __kernel_ipc_pid_t msg_lspid; /* pid of last msgsnd */ + __kernel_ipc_pid_t msg_lrpid; /* last receive pid */ +}; + +#endif + +struct msqid_ds { + struct msqid_ds_base u; + /* unions used to maintain size on 64 bit platforms */ + union { void * __wwait ; unsigned int msg_cbytes; } c; + union { void * __rwait ; unsigned int msg_qbytes; } q; + unsigned short old_msg_cbytes; /* current number of bytes on queue */ unsigned short msg_qnum; /* number of messages in queue */ - unsigned short msg_qbytes; /* max number of bytes on queue */ + unsigned short old_msg_qbytes; /* max number of bytes on queue */ __kernel_ipc_pid_t msg_lspid; /* pid of last msgsnd */ __kernel_ipc_pid_t msg_lrpid; /* last receive pid */ };

+#if 0 +#if !defined __KERNEL__ && (!defined(__GLIBC__) || __GLIBC__ < 2) +/* glibc < 2 doesn't have sys/msg.h -- do we support the use of 2.1 kernel + * headers on older systems? + */ +#define msg_perm u.msg_perm +#define msg_stime u.msg_stime +#define msg_rtime u.msg_rtime +#define msg_ctime u.msg_ctime +#define msg_cbytes c.msg_cbytes +#define msg_qbytes q.msg_qbytes +#endif +#endif + /* message buffer for msgsnd and msgrcv calls */ struct msgbuf { long mtype; /* type of message */ @@ -47,12 +81,15 @@ };

#define MSGMNI 128 /* <= 1K */ /* max # of msg queue identifiers */ -#define MSGMAX 4056 /* <= 4056 */ /* max size of message (bytes) */ -#define MSGMNB 16384 /* ? */ /* default max size of a message queue */ + +/* Default values, now configurable at run time */ +#define MSGMAX 4056 /* <= 4056 */ /* max size of message (bytes) */ +#define MSGMNB 16384 /* default max size of a message queue */ +#define __MSGPOOL (MSGMNI*MSGMNB) /* size of message pool */ +#define MSGPOOL (__MSGPOOL/1024) /* size in kilobytes of message pool */

/* unused */ -#define MSGPOOL (MSGMNI*MSGMNB/1024) /* size in kilobytes of message pool */ -#define MSGTQL MSGMNB /* number of system message headers */ +#define MSGTQL (MSGMNB*MSGMNI) /* max number of system message headers */ #define MSGMAP MSGMNB /* number of entries in message map */ #define MSGSSZ 16 /* message segment size */ #define __MSGSEG ((MSGPOOL*1024)/ MSGSSZ) /* max no. of segments */ @@ -66,7 +103,7 @@ long msg_type; char *msg_spot; /* message text address */ time_t msg_stime; /* msgsnd time */ - short msg_ts; /* message text size */ + int msg_ts; /* message text size */ };

asmlinkage int sys_msgget (key_t key, int msgflg); diff -ur linux-2.1.131.orig/include/linux/sysctl.h linux-2.1.131.clean/include/linux/sysctl.h --- linux-2.1.131.orig/include/linux/sysctl.h Sat Dec 5 01:34:18 1998 +++ linux-2.1.131.clean/include/linux/sysctl.h Sun Dec 6 08:41:14 1998 @@ -89,6 +89,10 @@ KERN_SG_BIG_BUFF=29, KERN_ACCT=30, /* BSD process accounting parameters */ KERN_PPC_L2CR=31, /* l2cr register on PPC */ + KERN_SHMMAX=32, /* int: Maximum shared memory segment */ + KERN_MSGMAX=33, /* int: Maximum size of a messege */ + KERN_MSGMNB=34, /* int: Maximum message queue size */ + KERN_MSGPOOL=35, /* int: Maximum system message pool size */ };

diff -ur linux-2.1.131.orig/ipc/msg.c linux-2.1.131.clean/ipc/msg.c --- linux-2.1.131.orig/ipc/msg.c Sat Dec 5 01:34:49 1998 +++ linux-2.1.131.clean/ipc/msg.c Sun Dec 6 09:16:19 1998 @@ -2,11 +2,12 @@ * linux/ipc/msg.c * Copyright (C) 1992 Krishna Balasubramanian * + * Remove 4056 byte MSGMAX restriction and 64K restrictions, limits made dynamic * Removed all the remaining kerneld mess * Catch the -EFAULT stuff properly * Use GFP_KERNEL for messages as in 1.2 * Fixed up the unchecked user space derefs - * Copyright (C) 1998 Alan Cox & Andi Kleen + * Copyright (C) 1998 Alan Cox, Andi Kleen & Peeter Joot * */

@@ -15,6 +16,7 @@ #include <linux/interrupt.h> #include <linux/smp_lock.h> #include <linux/init.h> +#include <linux/vmalloc.h>

#include <asm/uaccess.h>

@@ -24,7 +26,7 @@ static int newque (key_t key, int msgflg); static int findkey (key_t key);

-static struct msqid_ds *msgque[MSGMNI]; +static struct msqid_ds_kernel *msgque[MSGMNI]; static int msgbytes = 0; static int msghdrs = 0; static unsigned short msg_seq = 0; @@ -32,12 +34,16 @@ static int max_msqid = 0; static struct wait_queue *msg_lock = NULL;

+int msgmax = MSGMAX; +int msgmnb = MSGMNB; +int msgpool = __MSGPOOL; + void __init msg_init (void) { int id;

for (id = 0; id < MSGMNI; id++) - msgque[id] = (struct msqid_ds *) IPC_UNUSED; + msgque[id] = (struct msqid_ds_kernel *) IPC_UNUSED; msgbytes = msghdrs = msg_seq = max_msqid = used_queues = 0; msg_lock = NULL; return; @@ -45,13 +51,13 @@

static int real_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg) { - int id; - struct msqid_ds *msq; + int id, error; + struct msqid_ds_kernel *msq; struct ipc_perm *ipcp; struct msg *msgh; long mtype;

- if (msgsz > MSGMAX || (long) msgsz < 0 || msqid < 0) + if (msgsz > msgmax || (long) msgsz < 0 || msqid < 0) return -EINVAL; if (get_user(mtype, &msgp->mtype)) return -EFAULT; @@ -61,43 +67,54 @@ msq = msgque [id]; if (msq == IPC_UNUSED || msq == IPC_NOID) return -EINVAL; - ipcp = &msq->msg_perm; + ipcp = &msq->u.msg_perm;

slept: - if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) + if (msq->u.msg_perm.seq != (unsigned int) msqid / MSGMNI) return -EIDRM;

if (ipcperms(ipcp, S_IWUGO)) return -EACCES; - - if (msgsz + msq->msg_cbytes > msq->msg_qbytes) { - 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; - interruptible_sleep_on (&msq->wwait); - goto slept; - } + + /* There were two identical if statements here ? */ + if ((msgsz + msq->msg_cbytes > msq->msg_qbytes) || + (msgsz + msgbytes > msgpool)) { + /* still no space in queue */ + if (msgflg & IPC_NOWAIT) + return -EAGAIN; + if (signal_pending(current)) + return -EINTR; + interruptible_sleep_on (&msq->wwait); + goto slept; } - + /* allocate message header and text space*/ - msgh = (struct msg *) kmalloc (sizeof(*msgh) + msgsz, GFP_KERNEL); - if (!msgh) - return -ENOMEM; - msgh->msg_spot = (char *) (msgh + 1); + if (msgsz < MSGMAX) { + /* Standard small message: */ + msgh = (struct msg *) kmalloc (sizeof(*msgh) + msgsz, + GFP_KERNEL); + if (!msgh) + return -ENOMEM; + msgh->msg_spot = (char *) (msgh + 1); + } else { + msgh = (struct msg *) kmalloc (sizeof(*msgh), GFP_KERNEL); + if (!msgh) + return -ENOMEM; + msgh->msg_spot = (char *) vmalloc(msgsz); + if (!msgh->msg_spot) + kfree(msgh); + }

if (copy_from_user(msgh->msg_spot, msgp->mtext, msgsz)) { - kfree(msgh); - return -EFAULT; + error = -EFAULT; + goto free_buf; }

if (msgque[id] == IPC_UNUSED || msgque[id] == IPC_NOID - || msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) { - kfree(msgh); - return -EIDRM; + || msq->u.msg_perm.seq != (unsigned int) msqid / MSGMNI) { + error = -EIDRM; + goto free_buf; }

msgh->msg_next = NULL; @@ -105,25 +122,31 @@ msgh->msg_type = mtype; msgh->msg_stime = CURRENT_TIME;

- if (!msq->msg_first) - msq->msg_first = msq->msg_last = msgh; + if (!msq->u.msg_first) + msq->u.msg_first = msq->u.msg_last = msgh; else { - msq->msg_last->msg_next = msgh; - msq->msg_last = msgh; + msq->u.msg_last->msg_next = msgh; + msq->u.msg_last = msgh; } msq->msg_cbytes += msgsz; - msgbytes += msgsz; + msgbytes += msgsz; msghdrs++; msq->msg_qnum++; msq->msg_lspid = current->pid; - msq->msg_stime = CURRENT_TIME; + msq->u.msg_stime = CURRENT_TIME; wake_up (&msq->rwait); return 0; + +free_buf: + if (msgsz >= MSGMAX) + vfree(msgh->msg_spot); + kfree(msgh); + return error; }

static int real_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, int msgflg) { - struct msqid_ds *msq; + struct msqid_ds_kernel *msq; struct ipc_perm *ipcp; struct msg *tmsg, *leastp = NULL; struct msg *nmsg = NULL; @@ -136,7 +159,7 @@ msq = msgque [id]; if (msq == IPC_NOID || msq == IPC_UNUSED) return -EINVAL; - ipcp = &msq->msg_perm; + ipcp = &msq->u.msg_perm;

/* * find message of correct type. @@ -145,7 +168,7 @@ * msgtyp < 0 => get message with least type must be < abs(msgtype). */ while (!nmsg) { - if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) { + if (msq->u.msg_perm.seq != (unsigned int) msqid / MSGMNI) { return -EIDRM; } if (ipcperms (ipcp, S_IRUGO)) { @@ -153,23 +176,23 @@ }

if (msgtyp == 0) - nmsg = msq->msg_first; + nmsg = msq->u.msg_first; else if (msgtyp > 0) { if (msgflg & MSG_EXCEPT) { - for (tmsg = msq->msg_first; tmsg; + for (tmsg = msq->u.msg_first; tmsg; tmsg = tmsg->msg_next) if (tmsg->msg_type != msgtyp) break; nmsg = tmsg; } else { - for (tmsg = msq->msg_first; tmsg; + for (tmsg = msq->u.msg_first; tmsg; tmsg = tmsg->msg_next) if (tmsg->msg_type == msgtyp) break; nmsg = tmsg; } } else { - for (leastp = tmsg = msq->msg_first; tmsg; + for (leastp = tmsg = msq->u.msg_first; tmsg; tmsg = tmsg->msg_next) if (tmsg->msg_type < leastp->msg_type) leastp = tmsg; @@ -182,21 +205,21 @@ return -E2BIG; } msgsz = (msgsz > nmsg->msg_ts)? nmsg->msg_ts : msgsz; - if (nmsg == msq->msg_first) - msq->msg_first = nmsg->msg_next; + if (nmsg == msq->u.msg_first) + msq->u.msg_first = nmsg->msg_next; else { - for (tmsg = msq->msg_first; tmsg; + for (tmsg = msq->u.msg_first; tmsg; tmsg = tmsg->msg_next) if (tmsg->msg_next == nmsg) break; tmsg->msg_next = nmsg->msg_next; - if (nmsg == msq->msg_last) - msq->msg_last = tmsg; + if (nmsg == msq->u.msg_last) + msq->u.msg_last = tmsg; } if (!(--msq->msg_qnum)) - msq->msg_last = msq->msg_first = NULL; + msq->u.msg_last = msq->u.msg_first = NULL;

- msq->msg_rtime = CURRENT_TIME; + msq->u.msg_rtime = CURRENT_TIME; msq->msg_lrpid = current->pid; msgbytes -= nmsg->msg_ts; msghdrs--; @@ -205,6 +228,8 @@ if (put_user (nmsg->msg_type, &msgp->mtype) || copy_to_user (msgp->mtext, nmsg->msg_spot, msgsz)) msgsz = -EFAULT; + if (nmsg->msg_ts >= MSGMAX) + vfree(nmsg->msg_spot); kfree(nmsg); return msgsz; } else { /* did not find a message */ @@ -244,14 +269,14 @@ static int findkey (key_t key) { int id; - struct msqid_ds *msq; + struct msqid_ds_kernel *msq;

for (id = 0; id <= max_msqid; id++) { while ((msq = msgque[id]) == IPC_NOID) interruptible_sleep_on (&msg_lock); if (msq == IPC_UNUSED) continue; - if (key == msq->msg_perm.key) + if (key == msq->u.msg_perm.key) return id; } return -1; @@ -260,48 +285,48 @@ static int newque (key_t key, int msgflg) { int id; - struct msqid_ds *msq; + struct msqid_ds_kernel *msq; struct ipc_perm *ipcp;

for (id = 0; id < MSGMNI; id++) if (msgque[id] == IPC_UNUSED) { - msgque[id] = (struct msqid_ds *) IPC_NOID; + msgque[id] = (struct msqid_ds_kernel *) IPC_NOID; goto found; } return -ENOSPC;

found: - msq = (struct msqid_ds *) kmalloc (sizeof (*msq), GFP_KERNEL); + msq = (struct msqid_ds_kernel *) kmalloc (sizeof (*msq), GFP_KERNEL); if (!msq) { - msgque[id] = (struct msqid_ds *) IPC_UNUSED; + msgque[id] = (struct msqid_ds_kernel *) IPC_UNUSED; wake_up (&msg_lock); return -ENOMEM; } - ipcp = &msq->msg_perm; + ipcp = &msq->u.msg_perm; ipcp->mode = (msgflg & S_IRWXUGO); ipcp->key = key; ipcp->cuid = ipcp->uid = current->euid; ipcp->gid = ipcp->cgid = current->egid; - msq->msg_perm.seq = msg_seq; - msq->msg_first = msq->msg_last = NULL; + msq->u.msg_perm.seq = msg_seq; + msq->u.msg_first = msq->u.msg_last = NULL; msq->rwait = msq->wwait = NULL; msq->msg_cbytes = msq->msg_qnum = 0; msq->msg_lspid = msq->msg_lrpid = 0; - msq->msg_stime = msq->msg_rtime = 0; - msq->msg_qbytes = MSGMNB; - msq->msg_ctime = CURRENT_TIME; + msq->u.msg_stime = msq->u.msg_rtime = 0; + msq->msg_qbytes = msgmnb; + msq->u.msg_ctime = CURRENT_TIME; if (id > max_msqid) max_msqid = id; msgque[id] = msq; used_queues++; wake_up (&msg_lock); - return (unsigned int) msq->msg_perm.seq * MSGMNI + id; + return (unsigned int) msq->u.msg_perm.seq * MSGMNI + id; }

asmlinkage int sys_msgget (key_t key, int msgflg) { int id, ret = -EPERM; - struct msqid_ds *msq; + struct msqid_ds_kernel *msq;

lock_kernel(); if (key == IPC_PRIVATE) @@ -317,10 +342,10 @@ msq = msgque[id]; if (msq == IPC_UNUSED || msq == IPC_NOID) ret = -EIDRM; - else if (ipcperms(&msq->msg_perm, msgflg)) + else if (ipcperms(&msq->u.msg_perm, msgflg)) ret = -EACCES; else - ret = (unsigned int) msq->msg_perm.seq * MSGMNI + id; + ret = (unsigned int) msq->u.msg_perm.seq * MSGMNI + id; } unlock_kernel(); return ret; @@ -328,24 +353,26 @@

static void freeque (int id) { - struct msqid_ds *msq = msgque[id]; + struct msqid_ds_kernel *msq = msgque[id]; struct msg *msgp, *msgh;

- msq->msg_perm.seq++; + msq->u.msg_perm.seq++; msg_seq = (msg_seq+1) % ((unsigned)(1<<31)/MSGMNI); /* increment, but avoid overflow */ msgbytes -= msq->msg_cbytes; if (id == max_msqid) while (max_msqid && (msgque[--max_msqid] == IPC_UNUSED)); - msgque[id] = (struct msqid_ds *) IPC_UNUSED; + msgque[id] = (struct msqid_ds_kernel *) IPC_UNUSED; used_queues--; while (waitqueue_active(&msq->rwait) || waitqueue_active(&msq->wwait)) { wake_up (&msq->rwait); wake_up (&msq->wwait); schedule(); } - for (msgp = msq->msg_first; msgp; msgp = msgh ) { + for (msgp = msq->u.msg_first; msgp; msgp = msgh ) { msgh = msgp->msg_next; msghdrs--; + if (msgp->msg_ts >= MSGMAX) + vfree(msgp->msg_spot); kfree(msgp); } kfree(msq); @@ -354,9 +381,10 @@ asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf) { int id, err = -EINVAL; - struct msqid_ds *msq; + struct msqid_ds_kernel *msq; struct msqid_ds tbuf; struct ipc_perm *ipcp; + unsigned int msg_qbytes;

lock_kernel(); if (msqid < 0 || cmd < 0) @@ -370,17 +398,20 @@ { struct msginfo msginfo; msginfo.msgmni = MSGMNI; - msginfo.msgmax = MSGMAX; - msginfo.msgmnb = MSGMNB; - msginfo.msgmap = MSGMAP; - msginfo.msgpool = MSGPOOL; - msginfo.msgtql = MSGTQL; + msginfo.msgmax = msgmax; + msginfo.msgmnb = msgmnb; msginfo.msgssz = MSGSSZ; msginfo.msgseg = MSGSEG; if (cmd == MSG_INFO) { - msginfo.msgpool = used_queues; + /* was used_queues ? */ + msginfo.msgpool = msgbytes; msginfo.msgmap = msghdrs; - msginfo.msgtql = msgbytes; + /* was msgbytes ? */ + msginfo.msgtql = used_queues; + } else { + msginfo.msgpool = msgpool/1024; + msginfo.msgmap = MSGMAP; + msginfo.msgtql = MSGTQL; }

err = -EFAULT; @@ -399,16 +430,18 @@ if (msq == IPC_UNUSED || msq == IPC_NOID) goto out; err = -EACCES; - if (ipcperms (&msq->msg_perm, S_IRUGO)) + if (ipcperms (&msq->u.msg_perm, S_IRUGO)) goto out; - id = (unsigned int) msq->msg_perm.seq * MSGMNI + msqid; - tbuf.msg_perm = msq->msg_perm; - tbuf.msg_stime = msq->msg_stime; - tbuf.msg_rtime = msq->msg_rtime; - tbuf.msg_ctime = msq->msg_ctime; - tbuf.msg_cbytes = msq->msg_cbytes; + id = (unsigned int) msq->u.msg_perm.seq * MSGMNI + msqid; + tbuf.u.msg_perm = msq->u.msg_perm; + tbuf.u.msg_stime = msq->u.msg_stime; + tbuf.u.msg_rtime = msq->u.msg_rtime; + tbuf.u.msg_ctime = msq->u.msg_ctime; + tbuf.c.msg_cbytes = msq->msg_cbytes; + tbuf.q.msg_qbytes = msq->msg_qbytes; + tbuf.old_msg_cbytes = (unsigned short)msq->msg_cbytes; tbuf.msg_qnum = msq->msg_qnum; - tbuf.msg_qbytes = msq->msg_qbytes; + tbuf.old_msg_qbytes = (unsigned short)msq->msg_qbytes; tbuf.msg_lspid = msq->msg_lspid; tbuf.msg_lrpid = msq->msg_lrpid; err = -EFAULT; @@ -435,22 +468,24 @@ if (msq == IPC_UNUSED || msq == IPC_NOID) goto out; err = -EIDRM; - if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) + if (msq->u.msg_perm.seq != (unsigned int) msqid / MSGMNI) goto out; - ipcp = &msq->msg_perm; + ipcp = &msq->u.msg_perm;

switch (cmd) { case IPC_STAT: err = -EACCES; if (ipcperms (ipcp, S_IRUGO)) goto out; - tbuf.msg_perm = msq->msg_perm; - tbuf.msg_stime = msq->msg_stime; - tbuf.msg_rtime = msq->msg_rtime; - tbuf.msg_ctime = msq->msg_ctime; - tbuf.msg_cbytes = msq->msg_cbytes; + tbuf.u.msg_perm = msq->u.msg_perm; + tbuf.u.msg_stime = msq->u.msg_stime; + tbuf.u.msg_rtime = msq->u.msg_rtime; + tbuf.u.msg_ctime = msq->u.msg_ctime; + tbuf.c.msg_cbytes = msq->msg_cbytes; + tbuf.q.msg_qbytes = msq->msg_qbytes; + tbuf.old_msg_cbytes = (unsigned short)msq->msg_cbytes; tbuf.msg_qnum = msq->msg_qnum; - tbuf.msg_qbytes = msq->msg_qbytes; + tbuf.old_msg_qbytes = (unsigned short)msq->msg_qbytes; tbuf.msg_lspid = msq->msg_lspid; tbuf.msg_lrpid = msq->msg_lrpid; err = -EFAULT; @@ -463,14 +498,18 @@ current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN)) /* We _could_ check for CAP_CHOWN above, but we don't */ goto out; - if (tbuf.msg_qbytes > MSGMNB && !capable(CAP_SYS_RESOURCE)) + if (tbuf.old_msg_qbytes == 0) + msg_qbytes = tbuf.q.msg_qbytes; + else + msg_qbytes = tbuf.old_msg_qbytes; + if (msg_qbytes > msgmnb && !capable(CAP_SYS_RESOURCE)) goto out; - msq->msg_qbytes = tbuf.msg_qbytes; - ipcp->uid = tbuf.msg_perm.uid; - ipcp->gid = tbuf.msg_perm.gid; + msq->msg_qbytes = msg_qbytes; + ipcp->uid = tbuf.u.msg_perm.uid; + ipcp->gid = tbuf.u.msg_perm.gid; ipcp->mode = (ipcp->mode & ~S_IRWXUGO) | - (S_IRWXUGO & tbuf.msg_perm.mode); - msq->msg_ctime = CURRENT_TIME; + (S_IRWXUGO & tbuf.u.msg_perm.mode); + msq->u.msg_ctime = CURRENT_TIME; err = 0; goto out; case IPC_RMID: diff -ur linux-2.1.131.orig/ipc/shm.c linux-2.1.131.clean/ipc/shm.c --- linux-2.1.131.orig/ipc/shm.c Sat Dec 5 01:34:49 1998 +++ linux-2.1.131.clean/ipc/shm.c Sat Dec 5 01:38:20 1998 @@ -126,6 +126,8 @@ return (unsigned int) shp->u.shm_perm.seq * SHMMNI + id; }

+int shmmax = SHMMAX; + asmlinkage int sys_shmget (key_t key, int size, int shmflg) { struct shmid_kernel *shp; @@ -133,7 +135,7 @@

down(&current->mm->mmap_sem); lock_kernel(); - if (size < 0 || size > SHMMAX) { + if (size < 0 || size > shmmax) { err = -EINVAL; } else if (key == IPC_PRIVATE) { err = newseg(key, shmflg, size); @@ -228,7 +230,7 @@ if (!buf) goto out; shminfo.shmmni = SHMMNI; - shminfo.shmmax = SHMMAX; + shminfo.shmmax = shmmax; shminfo.shmmin = SHMMIN; shminfo.shmall = SHMALL; shminfo.shmseg = SHMSEG; diff -ur linux-2.1.131.orig/kernel/sysctl.c linux-2.1.131.clean/kernel/sysctl.c --- linux-2.1.131.orig/kernel/sysctl.c Sat Dec 5 01:34:49 1998 +++ linux-2.1.131.clean/kernel/sysctl.c Sun Dec 6 08:39:42 1998 @@ -42,6 +42,12 @@ #ifdef CONFIG_CHR_DEV_SG extern int sg_big_buff; #endif +#ifdef CONFIG_SYSVIPC +extern int shmmax; +extern int msgmax; +extern int msgmnb; +extern int msgpool; +#endif

#ifdef __sparc__ extern char reboot_command []; @@ -194,6 +200,16 @@ #ifdef CONFIG_BSD_PROCESS_ACCT {KERN_ACCT, "acct", &acct_parm, 3*sizeof(int), 0644, NULL, &proc_dointvec}, +#endif +#ifdef CONFIG_SYSVIPC + {KERN_SHMMAX, "shmmax", &shmmax, sizeof (int), + 0644, NULL, &proc_dointvec}, + {KERN_MSGMAX, "msgmax", &msgmax, sizeof (int), + 0644, NULL, &proc_dointvec}, + {KERN_MSGMNB, "msgmnb", &msgmnb, sizeof (int), + 0644, NULL, &proc_dointvec}, + {KERN_MSGPOOL, "msgpool", &msgpool, sizeof (int), + 0644, NULL, &proc_dointvec}, #endif {0} };

--------------------------------------------------------------------------- sys/msq_buf.h replacement: ---------------------------------------------------------------------------

/* Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, August 1995.

The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details.

You should have received a copy of the GNU Library General Public License along with the GNU C Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */

#ifndef _SYS_MSQ_BUF_H

#define _SYS_MSQ_BUF_H 1 #include <features.h>

#include <sys/types.h>

/* Define options for message queue functions. */ #define MSG_NOERROR 010000 /* no error if message is too big */ #define MSG_EXCEPT 020000 /* recv any msg except of specified type */

__BEGIN_DECLS

/* Structure of record for one message inside the kernel. The type `struct __msg' is opaque. */ struct msqid_ds { struct ipc_perm msg_perm; /* structure describing operation permission */ struct msg *__msg_first; /* pointer to first message on queue */ struct msg *__msg_last; /* pointer to last message on queue */ __time_t msg_stime; /* time of last msgsnd command */ __time_t msg_rtime; /* time of last msgrcv command */ __time_t msg_ctime; /* time of last change */ unsigned int __msg_cbytes; /* current number of bytes on queue */ #if defined(__alpha__) /* what is the proper 64 bit test macro for this */ unsigned int __pad0; #endif unsigned int msg_qbytes; /* max number of bytes allowed on queue */ #if defined(__alpha__) unsigned int __pad1; #endif unsigned short int __old_msg_cbytes; unsigned short int msg_qnum; /* number of messages currently on queue */ unsigned short int __old_msg_qbytes; __ipc_pid_t msg_lspid; /* pid of last msgsnd() */ __ipc_pid_t msg_lrpid; /* pid of last msgrcv() */ };

#ifdef __USE_MISC

#define msg_cbytes __msg_cbytes

/* ipcs ctl commands */ #define MSG_STAT 11 #define MSG_INFO 12

/* buffer for msgctl calls IPC_INFO, MSG_INFO */ struct msginfo { int msgpool; int msgmap; int msgmax; int msgmnb; int msgmni; int msgssz; int msgtql; ushort msgseg; };

#endif /* __USE_MISC */

__END_DECLS

#endif /* _SYS_MSQ_BUF_H */

--------------------------------------------------------------------------- msg_big.c -- defines my_msgctl() for use with above msq_buf.h -- to use #define msg_ctl to my_msgctl in other code. --------------------------------------------------------------------------- #include <sys/msg.h> #include <sys/sysctl.h> #include <unistd.h> #include <errno.h> #include <sys/types.h> #include <sys/ipc.h>

int __kernel_large_msqqueue_support = 0;

void __test_large_msqqueues (void) __attribute__ ((__constructor__));

void __test_large_msqqueues (void) { int rc; int name[] = {CTL_KERN, KERN_MSGMAX};

rc = sysctl (name, 2, 0, 0, 0, 0); if (rc == 0) __kernel_large_msqqueue_support = 1; }

#ifndef MSG_STAT #define MSG_STAT 11 #endif

#ifdef msgctl #undef msgctl #endif

int my_msgctl (int msqid, int cmd, struct msqid_ds *buf) { int rc; switch (cmd) { case MSG_STAT: case IPC_STAT: if (!buf) { errno = EINVAL; return -1; } rc = msgctl (msqid, cmd, buf); if (__kernel_large_msqqueue_support == 0 && rc == 0 && errno != EFAULT) { buf->msg_qbytes = buf->__old_msg_qbytes; buf->__msg_cbytes = buf->__old_msg_cbytes; } return rc; case IPC_SET: if (!buf) { errno = EINVAL; return -1; } /* This alters the semantics of the system call slightly, as * it would be possible to get a segv here, rather than a polite * -1 return code and EFAULT errno -- I don't think it is a big deal. */ if (__kernel_large_msqqueue_support == 0) buf->__old_msg_qbytes = buf->msg_qbytes; else buf->__old_msg_qbytes = 0; default: return msgctl (msqid, cmd, buf); } }

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/