The patch is mostly tested, and if you want to test it you must
apply it to 2.3.26-2.
-- Manfred <<<<<<<<<<<<<< // $Header: /pub/cvs/ms/patches/patch-ipcmerge,v 1.9 1999/11/05 23:46:31 manfreds Exp $ // Kernel Version: // VERSION = 2 // PATCHLEVEL = 3 // SUBLEVEL = 26 // EXTRAVERSION = --- 2.3/ipc/sem.c Tue Nov 2 16:14:34 1999 +++ build-2.3/ipc/sem.c Sat Nov 6 00:44:29 1999 @@ -59,120 +59,91 @@ #include <linux/spinlock.h> #include <linux/init.h> #include <linux/proc_fs.h> - #include <asm/uaccess.h> +#include "util.h" + + +#define sem_lock(id) ((struct semid_ds*)ipc_lock(&sem_ids,id)) +#define sem_unlock(id) ipc_unlock(&sem_ids,id) +#define sem_rmid(id) ((struct semid_ds*)ipc_rmid(&sem_ids,id)) +#define sem_checkid(sma, semid) \ + ipc_checkid(&sem_ids,&sma->sem_perm,semid) +#define sem_buildid(id, seq) \ + ipc_buildid(&sem_ids, id, seq) +static struct ipc_ids sem_ids; -extern int ipcperms (struct ipc_perm *ipcp, short semflg); static int newary (key_t, int, int); -static int findkey (key_t key); static void freeary (int id); #ifdef CONFIG_PROC_FS static int sysvipc_sem_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data); #endif -struct semid_ary -{ - spinlock_t lock; - struct semid_ds* s; -}; - -static struct semid_ary semary[SEMMNI]; - -static DECLARE_MUTEX(sem_lock); -static int max_semid = 0; -static int used_sems = 0; -static int used_semids = 0; - -static unsigned short sem_seq = 0; - -/* anti-deadlock ordering: - * sem_lock < semary[].lock +#define SEMMSL_FAST 256 /* 512 bytes on stack */ +#define SEMOPM_FAST 64 /* ~ 372 bytes on stack */ +/* * linked list protection: * sem_undo.id_next, * semid_ds.sem_pending{,last}, - * semid_ds.sem_undo: semary[].lock for read/write + * semid_ds.sem_undo: sem_lock() for read/write * sem_undo.proc_next: only "current" is allowed to read/write that field. * */ +int sem_ctls[4] = {SEMMSL, SEMMNS, SEMOPM, SEMMNI}; +#define sc_semmsl (sem_ctls[0]) +#define sc_semmns (sem_ctls[1]) +#define sc_semopm (sem_ctls[2]) +#define sc_semmni (sem_ctls[3]) + +static int used_sems = 0; + void __init sem_init (void) { - int i; + used_sems = 0; + ipc_init_ids(&sem_ids,sc_semmni); - used_sems = used_semids = max_semid = sem_seq = 0; - for (i = 0; i < SEMMNI; i++) { - semary[i].lock = SPIN_LOCK_UNLOCKED; - semary[i].s = NULL; - } #ifdef CONFIG_PROC_FS create_proc_read_entry("sysvipc/sem", 0, 0, sysvipc_sem_read_proc, NULL); #endif - return; -} - -static int findkey (key_t key) -{ - int id; - struct semid_ds *sma; - - for (id = 0; id <= max_semid; id++) { - sma = semary[id].s; - if(sma==NULL) - continue; - - if (key == sma->sem_perm.key) - return id; - } - return -1; } static int newary (key_t key, int nsems, int semflg) { int id; struct semid_ds *sma; - struct ipc_perm *ipcp; int size; if (!nsems) return -EINVAL; - if (used_sems + nsems > SEMMNS) + if (used_sems + nsems > sc_semmns) return -ENOSPC; - for (id = 0; id < SEMMNI; id++) { - if(semary[id].s == NULL) - goto found; - } - return -ENOSPC; -found: + size = sizeof (*sma) + nsems * sizeof (struct sem); - used_sems += nsems; - sma = (struct semid_ds *) kmalloc (size, GFP_KERNEL); + ipc_grow_ids(&sem_ids, sc_semmni); + sma = (struct semid_ds *) ipc_alloc(size); if (!sma) { - used_sems -= nsems; return -ENOMEM; } memset (sma, 0, size); + id = ipc_addid(&sem_ids, &sma->sem_perm); + if(id == -1) { + ipc_free(sma, size); + return -ENOSPC; + } + used_sems += nsems; + + sma->sem_perm.mode = (semflg & S_IRWXUGO); + sma->sem_perm.key = key; + sma->sem_base = (struct sem *) &sma[1]; - ipcp = &sma->sem_perm; - ipcp->mode = (semflg & S_IRWXUGO); - ipcp->key = key; - ipcp->cuid = ipcp->uid = current->euid; - ipcp->gid = ipcp->cgid = current->egid; - /* sma->sem_perm.seq*MSGMNI must be a positive integer. - * this limits MSGMNI to 32768 - */ - sma->sem_perm.seq = sem_seq++; - /* sma->sem_pending = NULL; */ + /* sma->sem_pending = NULL; */ sma->sem_pending_last = &sma->sem_pending; /* sma->undo = NULL; */ sma->sem_nsems = nsems; sma->sem_ctime = CURRENT_TIME; - if (id > max_semid) - max_semid = id; - used_semids++; - spin_lock(&semary[id].lock); - semary[id].s = sma; - spin_unlock(&semary[id].lock); - return (unsigned int) sma->sem_perm.seq * SEMMNI + id; + sem_unlock(id); + + return sem_buildid(id, sma->sem_perm.seq); } asmlinkage long sys_semget (key_t key, int nsems, int semflg) @@ -180,13 +151,13 @@ int id, err = -EINVAL; struct semid_ds *sma; - if (nsems < 0 || nsems > SEMMSL) + if (nsems < 0 || nsems > sc_semmsl) return -EINVAL; - down(&sem_lock); + down(&sem_ids.sem); if (key == IPC_PRIVATE) { err = newary(key, nsems, semflg); - } else if ((id = findkey (key)) == -1) { /* key not used */ + } else if ((id = ipc_findkey(&sem_ids, key)) == -1) { /* key not used */ if (!(semflg & IPC_CREAT)) err = -ENOENT; else @@ -194,19 +165,39 @@ } else if (semflg & IPC_CREAT && semflg & IPC_EXCL) { err = -EEXIST; } else { - sma = semary[id].s; + sma = sem_lock(id); + if(sma==NULL) + BUG(); 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; + err = sem_buildid(id, sma->sem_perm.seq); + sem_unlock(id); } - up(&sem_lock); + up(&sem_ids.sem); return err; } +static int sem_revalidate(int semid, struct semid_ds* sma, int nsems, short flg) +{ + struct semid_ds* smanew; + + smanew = sem_lock(semid); + + if(smanew != sma) + return -EIDRM; + if(sem_checkid(sma,semid)) + return -EIDRM; + if(sma->sem_nsems != nsems) + return -EIDRM; + + if (ipcperms(&sma->sem_perm, flg)) + return -EACCES; + return 0; +} /* Manage the doubly linked list sma->sem_pending as a FIFO: * insert new queue elements at the tail sma->sem_pending_last. */ @@ -387,15 +378,9 @@ struct semid_ds *sma; struct sem_undo *un; struct sem_queue *q; + int size; - /* we own both locks, noone can get in */ - sma = semary[id].s; - semary[id].s = NULL; - - used_sems -= sma->sem_nsems; - if (id == max_semid) - while (max_semid && (semary[--max_semid].s == NULL)); - used_semids--; + sma = sem_rmid(id); /* Invalidate the existing undo structures for this semaphore set. * (They will be freed without any further action in sem_exit() @@ -410,40 +395,45 @@ q->prev = NULL; wake_up_process(q->sleeper); /* doesn't sleep */ } + sem_unlock(id); - kfree(sma); + used_sems -= sma->sem_nsems; + size = sizeof (*sma) + sma->sem_nsems * sizeof (struct sem); + ipc_free(sma, size); } int semctl_nolock(int semid, int semnum, int cmd, union semun arg) { int err = -EINVAL; - int lid = semid % SEMMNI; switch(cmd) { case IPC_INFO: case SEM_INFO: { struct seminfo seminfo; + int max_id; - seminfo.semmni = SEMMNI; - seminfo.semmns = SEMMNS; - seminfo.semmsl = SEMMSL; - seminfo.semopm = SEMOPM; + memset(&seminfo,0,sizeof(seminfo)); + seminfo.semmni = sc_semmni; + seminfo.semmns = sc_semmns; + seminfo.semmsl = sc_semmsl; + seminfo.semopm = sc_semopm; seminfo.semvmx = SEMVMX; seminfo.semmnu = SEMMNU; seminfo.semmap = SEMMAP; seminfo.semume = SEMUME; seminfo.semusz = SEMUSZ; seminfo.semaem = SEMAEM; + down(&sem_ids.sem); if (cmd == SEM_INFO) { - down(&sem_lock); - seminfo.semusz = used_semids; + seminfo.semusz = sem_ids.in_use; seminfo.semaem = used_sems; - up(&sem_lock); } + max_id = sem_ids.max_id; + up(&sem_ids.sem); if (copy_to_user (arg.__buf, &seminfo, sizeof(struct seminfo))) return -EFAULT; - return max_semid; + return (max_id < 0) ? 0: max_id; } case SEM_STAT: { @@ -451,24 +441,24 @@ struct semid_ds tbuf; int id; - if (semid > max_semid) + if(semid > sem_ids.size) return -EINVAL; - spin_lock(&semary[lid].lock); + sma = sem_lock(semid); err = -EINVAL; - sma = semary[semid].s; - if (sma == NULL) + if(sma == NULL) goto out_unlock; err = -EACCES; if (ipcperms (&sma->sem_perm, S_IRUGO)) goto out_unlock; - id = (unsigned int) sma->sem_perm.seq * SEMMNI + semid; + id = sem_buildid(semid, sma->sem_perm.seq); + memset(&tbuf,0,sizeof(tbuf)); tbuf.sem_perm = sma->sem_perm; tbuf.sem_otime = sma->sem_otime; tbuf.sem_ctime = sma->sem_ctime; tbuf.sem_nsems = sma->sem_nsems; - spin_unlock(&semary[lid].lock); + sem_unlock(semid); if (copy_to_user (arg.buf, &tbuf, sizeof(tbuf))) return -EFAULT; return id; @@ -478,99 +468,139 @@ } return err; out_unlock: - spin_unlock(&semary[lid].lock); + sem_unlock(semid); return err; } -int semctl_locked_unlock(int semid, int semnum, int cmd, union semun arg) +int semctl_main(int semid, int semnum, int cmd, union semun arg) { struct semid_ds *sma; - struct semid_ds tbuf; + struct sem* curr; int err; - int lid = semid % SEMMNI; + ushort fast_sem_io[SEMMSL_FAST]; + ushort* sem_io = fast_sem_io; + int nsems; - sma = semary[lid].s; + sma = sem_lock(semid); err=-EINVAL; if (sma == NULL) goto out_unlock; err=-EIDRM; - if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI) + if (sem_checkid(sma,semid)) goto out_unlock; err = -EACCES; - if (ipcperms(&sma->sem_perm, S_IRUGO)) - goto out_unlock; - + if (ipcperms (&sma->sem_perm, (cmd==SETVAL||cmd==SETALL)?S_IWUGO:S_IRUGO)) + goto out_unlock; + + nsems = sma->sem_nsems; switch (cmd) { case GETALL: { ushort *array = arg.array; - ushort sem_io[SEMMSL]; int i; - int nsems = sma->sem_nsems; + + if(nsems > SEMMSL_FAST) { + sem_unlock(semid); + sem_io = ipc_alloc(sizeof(ushort)*nsems); + if(sem_io == NULL) + return -ENOMEM; + err = sem_revalidate(semid, sma, nsems, S_IRUGO); + if(err) + goto out_unlock; + } for (i = 0; i < sma->sem_nsems; i++) sem_io[i] = sma->sem_base[i].semval; - spin_unlock(&semary[lid].lock); + sem_unlock(semid); + err = 0; if (copy_to_user (array, sem_io, nsems*sizeof(ushort))) + err = -EFAULT; + if(sem_io != fast_sem_io) + ipc_free(sem_io, sizeof(ushort)*nsems); + return err; + } + case SETALL: + { + int i; + struct sem_undo *un; + + sem_unlock(semid); + + if(nsems > SEMMSL_FAST) { + sem_io = ipc_alloc(sizeof(ushort)*nsems); + if(sem_io == NULL) + return -ENOMEM; + } + + if (copy_from_user (sem_io, arg.array, nsems*sizeof(ushort))) { + if(sem_io != fast_sem_io) + ipc_free(sem_io, sizeof(ushort)*nsems); return -EFAULT; - return 0; + } + for (i = 0; i < nsems; i++) { + if (sem_io[i] > SEMVMX) { + if(sem_io != fast_sem_io) + ipc_free(sem_io, sizeof(ushort)*nsems); + return -ERANGE; + } + } + err = sem_revalidate(semid, sma, nsems, S_IRUGO); + if(err) + goto out_unlock; + for (i = 0; i < nsems; i++) + sma->sem_base[i].semval = sem_io[i]; + for (un = sma->undo; un; un = un->id_next) + for (i = 0; i < nsems; i++) + un->semadj[i] = 0; + sma->sem_ctime = CURRENT_TIME; + /* maybe some queued-up processes were waiting for this */ + update_queue(sma); + err = 0; + goto out_unlock; } + case IPC_STAT: + { + struct semid_ds tbuf; memset(&tbuf,0,sizeof(tbuf)); tbuf.sem_perm = sma->sem_perm; tbuf.sem_otime = sma->sem_otime; tbuf.sem_ctime = sma->sem_ctime; tbuf.sem_nsems = sma->sem_nsems; - spin_unlock(&semary[lid].lock); + sem_unlock(semid); if (copy_to_user (arg.buf, &tbuf, sizeof(tbuf))) return -EFAULT; return 0; -default: - err = -EINVAL; } -out_unlock: - spin_unlock(&semary[lid].lock); - return err; - -} - -int semctl_locked(int semid, int semnum, int cmd, union semun arg) -{ - struct semid_ds *sma; - int lid = semid % SEMMNI; - struct sem *curr; - - sma = semary[lid].s; - if (sma == NULL) - return -EINVAL; - - if (ipcperms (&sma->sem_perm, (cmd==SETVAL)?S_IWUGO:S_IRUGO)) - return -EACCES; - - if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI) - return -EIDRM; - - if (semnum >= sma->sem_nsems) - return -EINVAL; + /* GETVAL, GETPID, GETNCTN, GETZCNT, SETVAL: fall-through */ + } + err = -EINVAL; + if (semnum >= nsems) + goto out_unlock; curr = &sma->sem_base[semnum]; switch (cmd) { case GETVAL: - return curr->semval; + err = curr->semval; + goto out_unlock; case GETPID: - return curr->sempid & 0xffff; + err = curr->sempid & 0xffff; + goto out_unlock; case GETNCNT: - return count_semncnt(sma,semnum); + err = count_semncnt(sma,semnum); + goto out_unlock; case GETZCNT: - return count_semzcnt(sma,semnum); + err = count_semzcnt(sma,semnum); + goto out_unlock; case SETVAL: { int val = arg.val; struct sem_undo *un; + err = -ERANGE; if (val > SEMVMX || val < 0) - return -ERANGE; + goto out_unlock; for (un = sma->undo; un; un = un->id_next) un->semadj[semnum] = 0; @@ -578,17 +608,25 @@ sma->sem_ctime = CURRENT_TIME; /* maybe some queued-up processes were waiting for this */ update_queue(sma); - return 0; + err = 0; + goto out_unlock; } + + default: + err = -EINVAL; } - return -EINVAL; +out_unlock: + sem_unlock(semid); + if(sem_io != fast_sem_io) + ipc_free(sem_io, sizeof(ushort)*nsems); + return err; + } int semctl_down(int semid, int semnum, int cmd, union semun arg) { struct semid_ds *sma; int err; - int lid = semid % SEMMNI; struct semid_ds tbuf; struct ipc_perm *ipcp; @@ -596,66 +634,25 @@ if(copy_from_user (&tbuf, arg.buf, sizeof (tbuf))) return -EFAULT; } - spin_lock(&semary[lid].lock); - sma = semary[lid].s; + sma = sem_lock(semid); err=-EINVAL; if (sma == NULL) goto out_unlock; + if (sem_checkid(sma,semid)) { + err=-EIDRM; + goto out_unlock; + } ipcp = &sma->sem_perm; - if(cmd == SETALL) { - int i; - struct sem_undo *un; - unsigned int nsems; - ushort sem_io[SEMMSL]; - /* SETALL doesn't belong into this - * group, but I need the semaphore - * for atomically reading nsems - * and changing the semaphore values - */ - err=-EACCES; - if (ipcperms (ipcp, S_IWUGO)) - goto out_unlock; - nsems=sma->sem_nsems; - spin_unlock(&semary[lid].lock); - - if (copy_from_user (sem_io, arg.array, nsems*sizeof(ushort))) - return -EFAULT; - for (i = 0; i < nsems; i++) { - if (sem_io[i] > SEMVMX) { - return -ERANGE; - } - } - /* we still own sem_lock, ie neither ownership - * nor permissions of the sem array could - * have changed. Just continue. - */ - spin_lock(&semary[lid].lock); - for (i = 0; i < nsems; i++) - sma->sem_base[i].semval = sem_io[i]; - for (un = sma->undo; un; un = un->id_next) - for (i = 0; i < nsems; i++) - un->semadj[i] = 0; - sma->sem_ctime = CURRENT_TIME; - /* maybe some queued-up processes were waiting for this */ - update_queue(sma); - err = 0; - goto out_unlock; - } - if (current->euid != ipcp->cuid && current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN)) { err=-EPERM; goto out_unlock; } - if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI) { - err=-EIDRM; - goto out_unlock; - } switch(cmd){ case IPC_RMID: - freeary(lid); + freeary(semid); err = 0; break; case IPC_SET: @@ -664,27 +661,28 @@ ipcp->mode = (ipcp->mode & ~S_IRWXUGO) | (tbuf.sem_perm.mode & S_IRWXUGO); sma->sem_ctime = CURRENT_TIME; + sem_unlock(semid); err = 0; break; default: err = -EINVAL; + sem_unlock(semid); + break; } + return err; out_unlock: - spin_unlock(&semary[lid].lock); + sem_unlock(semid); return err; } asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg) { - int lid; /* lock id */ int err = -EINVAL; if (semid < 0 || semnum < 0 || cmd < 0) return -EINVAL; - lid = semid % SEMMNI; - switch(cmd) { case IPC_INFO: case SEM_INFO: @@ -693,24 +691,20 @@ return err; case GETALL: case IPC_STAT: - spin_lock(&semary[lid].lock); - err = semctl_locked_unlock(semid,semnum,cmd,arg); - return err; + case GETVAL: case GETPID: case GETNCNT: case GETZCNT: case SETVAL: - spin_lock(&semary[lid].lock); - err= semctl_locked(semid,semnum,cmd,arg); - spin_unlock(&semary[lid].lock); - return err; case SETALL: + err = semctl_main(semid,semnum,cmd,arg); + return err; case IPC_RMID: case IPC_SET: - down(&sem_lock); + down(&sem_ids.sem); err= semctl_down(semid,semnum,cmd,arg); - up(&sem_lock); + up(&sem_ids.sem); return err; default: return -EINVAL; @@ -736,30 +730,22 @@ static int alloc_undo(struct semid_ds *sma, struct sem_undo** unp, int semid, int alter) { - int size; + int size, nsems, error; struct sem_undo *un; - int error,id; - id = (unsigned int) semid % SEMMNI; - size = sizeof(struct sem_undo) + sizeof(short)*sma->sem_nsems; - spin_unlock(&semary[id].lock); + + nsems = sma->sem_nsems; + size = sizeof(struct sem_undo) + sizeof(short)*nsems; + sem_unlock(semid); un = (struct sem_undo *) kmalloc(size, GFP_KERNEL); - spin_lock(&semary[id].lock); - if (!un) { + error = sem_revalidate(semid, sma, nsems, alter ? S_IWUGO : S_IRUGO); + if (!un) return -ENOMEM; - } - sma = semary[id].s; - error = -EIDRM; - if (sma == NULL) - goto out; - if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI) - goto out; - if (size != sizeof(struct sem_undo) + sizeof(short)*sma->sem_nsems) - goto out; - error = -EACCES; - if (ipcperms(&sma->sem_perm, alter ? S_IWUGO : S_IRUGO)) - goto out; + if(error) { + kfree(un); + return error; + } memset(un, 0, size); un->semadj = (short *) &un[1]; un->semid = semid; @@ -769,16 +755,14 @@ sma->undo = un; *unp = un; return 0; -out: - kfree(un); - return error; } asmlinkage long sys_semop (int semid, struct sembuf *tsops, unsigned nsops) { - int id, error = -EINVAL; + int error = -EINVAL; struct semid_ds *sma; - struct sembuf sops[SEMOPM], *sop; + struct sembuf fast_sops[SEMOPM_FAST]; + struct sembuf* sops = fast_sops, *sop; struct sem_undo *un; int undos = 0, decrease = 0, alter = 0; struct sem_queue queue; @@ -786,19 +770,25 @@ if (nsops < 1 || semid < 0) return -EINVAL; - if (nsops > SEMOPM) + if (nsops > sc_semopm) return -E2BIG; - if (copy_from_user (sops, tsops, nsops * sizeof(*tsops))) + if(nsops > SEMOPM_FAST) { + sops = kmalloc(sizeof(*sops)*nsops,GFP_KERNEL); + if(sops==NULL) + return -ENOMEM; + } + if (copy_from_user (sops, tsops, nsops * sizeof(*tsops))) { + if(sops != fast_sops) + kfree(sops); return -EFAULT; + } - id = (unsigned int) semid % SEMMNI; - spin_lock(&semary[id].lock); - sma = semary[id].s; + sma = sem_lock(semid); error = -EINVAL; if (sma == NULL) goto out; error = -EIDRM; - if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI) + if (sem_checkid(sma,semid)) goto out; error = -EFBIG; @@ -852,7 +842,7 @@ queue.undo = un; queue.pid = current->pid; queue.alter = decrease; - queue.id = id; + queue.id = semid; current->semsleeping = &queue; if (alter) append_to_queue(sma ,&queue); @@ -863,14 +853,14 @@ queue.status = -EINTR; queue.sleeper = current; current->state = TASK_INTERRUPTIBLE; - spin_unlock(&semary[id].lock); + sem_unlock(semid); schedule(); /* we can lock the semary even if it was * deleted. */ - spin_lock(&semary[id].lock); + sem_lock(semid); /* * If queue.status == 1 we where woken up and * have to retry else we simply return. @@ -899,7 +889,9 @@ if (alter) update_queue (sma); out: - spin_unlock(&semary[id].lock); + sem_unlock(semid); + if(sops != fast_sops) + kfree(sops); return error; } @@ -930,29 +922,27 @@ * No synchronization required. */ if ((q = current->semsleeping)) { - spin_lock(&semary[current->semsleeping->id].lock); + int semid = current->semsleeping->id; + sem_lock(semid); + current->semsleeping = NULL; if (q->prev) remove_from_queue(q->sma,q); - current->semsleeping = NULL; - spin_unlock(&semary[current->semsleeping->id].lock); + sem_unlock(semid); } for (up = ¤t->semundo; (u = *up); *up = u->proc_next, kfree(u)) { int semid = u->semid; - int lid; if(semid == -1) continue; - lid = semid % SEMMNI; - spin_lock(&semary[lid].lock); + sma = sem_lock(semid); if (u->semid == -1) goto next_entry; - sma = semary[lid].s; if (sma == NULL) goto next_entry; - if (sma->sem_perm.seq != (unsigned int) u->semid / SEMMNI) + if (sem_checkid(sma,u->semid)) goto next_entry; /* remove u from the sma->undo list */ @@ -977,7 +967,7 @@ /* maybe some queued-up processes were waiting for this */ update_queue(sma); next_entry: - spin_unlock(&semary[lid].lock); + sem_unlock(semid); } current->semundo = NULL; } @@ -990,35 +980,37 @@ int i, len = 0; len += sprintf(buffer, " key semid perms nsems uid gid cuid cgid otime ctime\n"); - down(&sem_lock); + down(&sem_ids.sem); - for(i = 0; i < SEMMNI; i++) - if(semary[i].s != NULL) { - spin_lock(&semary[i].lock); + for(i = 0; i < sem_ids.max_id; i++) { + struct semid_ds *sma; + sma = sem_lock(i); + if(sma) { len += sprintf(buffer + len, "%10d %10d %4o %5u %5u %5u %5u %5u %10lu %10lu\n", - semary[i].s->sem_perm.key, - semary[i].s->sem_perm.seq * SEMMNI + i, - semary[i].s->sem_perm.mode, - semary[i].s->sem_nsems, - semary[i].s->sem_perm.uid, - semary[i].s->sem_perm.gid, - semary[i].s->sem_perm.cuid, - semary[i].s->sem_perm.cgid, - semary[i].s->sem_otime, - semary[i].s->sem_ctime); - spin_unlock(&semary[i].lock); - - pos += len; - if(pos < offset) { - len = 0; - begin = pos; - } - if(pos > offset + length) - goto done; + sma->sem_perm.key, + sem_buildid(i,sma->sem_perm.seq), + sma->sem_perm.mode, + sma->sem_nsems, + sma->sem_perm.uid, + sma->sem_perm.gid, + sma->sem_perm.cuid, + sma->sem_perm.cgid, + sma->sem_otime, + sma->sem_ctime); } + sem_unlock(i); + + pos += len; + if(pos < offset) { + len = 0; + begin = pos; + } + if(pos > offset + length) + goto done; + } *eof = 1; done: - up(&sem_lock); + up(&sem_ids.sem); *start = buffer + (offset - begin); len -= (offset - begin); if(len > length) --- 2.3/ipc/util.c Fri Nov 5 16:35:35 1999 +++ build-2.3/ipc/util.c Sat Nov 6 00:30:04 1999 @@ -13,6 +13,9 @@ #include <linux/shm.h> #include <linux/init.h> #include <linux/msg.h> +#include <linux/smp_lock.h> +#include <linux/vmalloc.h> +#include <linux/malloc.h> #include "util.h" @@ -26,6 +29,137 @@ msg_init(); shm_init(); return; +} + +void __init ipc_init_ids(struct ipc_ids* ids, int size) +{ + int i; + sema_init(&ids->sem,1); + ids->size = size; + if(size == 0) + return; + if(size > IPCMNI) + size = IPCMNI; + + ids->in_use = 0; + ids->max_id = -1; + ids->seq = 0; + { + int seq_limit = INT_MAX/SEQ_MULTIPLIER; + if(seq_limit > USHRT_MAX) + ids->seq_max = USHRT_MAX; + else + ids->seq_max = seq_limit; + } + + ids->entries = ipc_alloc(sizeof(struct ipc_id)*size); + + if(ids->entries == NULL) { + printk(KERN_ERR "ipc_init_ids() failed, ipc service disabled.\n"); + ids->size = 0; + } + for(i=0;i<size;i++) + ids->entries[i].lock = SPIN_LOCK_UNLOCKED; +} + +/* must be called with ids->sem acquired.*/ +void ipc_grow_ids(struct ipc_ids* ids, int newsize) +{ + if(newsize <= ids->size) + return; /* nothing to do */ + /* FIXME: grow the array: + * a) allocate new memory + * b) synchronize ? + * c) replace the array + * d) free the old array. + */ +} + +int ipc_findkey(struct ipc_ids* ids, key_t key) +{ + int id; + struct ipc_perm* p; + + for (id = 0; id <= ids->max_id; id++) { + p = ids->entries[id].p; + if(p==NULL) + continue; + if (key == p->key) + return id; + } + return -1; +} + +int ipc_addid(struct ipc_ids* ids, struct ipc_perm* new) +{ + int id; + for (id = 0; id < ids->size; id++) { + if(ids->entries[id].p == NULL) + goto found; + } + return -1; +found: + ids->in_use++; + if (id > ids->max_id) + ids->max_id = id; + + new->cuid = new->uid = current->euid; + new->gid = new->cgid = current->egid; + + new->seq = ids->seq++; + if(ids->seq > ids->seq_max) + ids->seq = 0; + + ipc_lock(ids,id); + ids->entries[id].p = new; + return id; +} + +struct ipc_perm* ipc_rmid(struct ipc_ids* ids, int id) +{ + struct ipc_perm* p; + int lid = id % SEQ_MULTIPLIER; + if(lid > ids->size) + BUG(); + p = ids->entries[lid].p; + ids->entries[lid].p = NULL; + if(p==NULL) + BUG(); + ids->in_use--; + + if (lid == ids->max_id) { + do { + lid--; + if(lid == -1) + break; + } while (ids->entries[lid].p == NULL); + ids->max_id = lid; + } + return p; +} + +void* ipc_alloc(int size) +{ + void* out; + if(size > PAGE_SIZE) { + lock_kernel(); + out = vmalloc(size); + unlock_kernel(); + } else { + out = kmalloc(size, GFP_KERNEL); + } + return out; +} + +void ipc_free(void* ptr, int size) +{ + if(size > PAGE_SIZE) { + lock_kernel(); + vfree(ptr); + unlock_kernel(); + } else { + kfree(ptr); + } } /* --- 2.3/ipc/util.h Fri Nov 5 16:35:35 1999 +++ build-2.3/ipc/util.h Fri Nov 5 23:53:19 1999 @@ -3,10 +3,69 @@ * Copyright (C) 1999 Christoph Rohland */ -/* - * IPCMNI is the absolute maximum for ipc identifier. This is used to - * detect stale identifiers - */ -#define IPCMNI (1<<15) +#define USHRT_MAX 0xffff -extern int ipcperms (struct ipc_perm *ipcp, short shmflg); +#define SEQ_MULTIPLIER (IPCMNI) +struct ipc_id { + spinlock_t lock; + struct ipc_perm* p; +}; + +struct ipc_ids { + int size; + int in_use; + int max_id; + unsigned short seq; + unsigned short seq_max; + struct semaphore sem; + struct ipc_id* entries; +}; + +void __init ipc_init_ids(struct ipc_ids* ids, int size); + +/* must be called with ids->sem acquired.*/ +void ipc_grow_ids(struct ipc_ids* ids, int newsize); + +/* must be called with ids->sem acquired.*/ +int ipc_findkey(struct ipc_ids* ids, key_t key); +int ipc_addid(struct ipc_ids* ids, struct ipc_perm* new); + +/* must be called with both locks acquired. */ +struct ipc_perm* ipc_rmid(struct ipc_ids* ids, int id); + +/* can be called both with and without ids->sem */ +extern inline struct ipc_perm* ipc_lock(struct ipc_ids* ids, int id) +{ + int lid = id % SEQ_MULTIPLIER; + if(lid > ids->size) + return NULL; + spin_lock(&ids->entries[lid].lock); + return ids->entries[lid].p; +} + +extern inline void ipc_unlock(struct ipc_ids* ids, int id) +{ + int lid = id % SEQ_MULTIPLIER; + if(lid > ids->size) + return; + spin_unlock(&ids->entries[lid].lock); +} + +/* for rare, potentially huge allocations.*/ +void ipc_free(void* ptr, int size); +void* ipc_alloc(int size); + + +int ipcperms (struct ipc_perm *ipcp, short flg); + +extern inline int ipc_buildid(struct ipc_ids* ids, int id, int seq) +{ + return SEQ_MULTIPLIER*seq + id; +} + +extern inline int ipc_checkid(struct ipc_ids* ids, struct ipc_perm* ipcp, int uid) +{ + if(uid/SEQ_MULTIPLIER != ipcp->seq) + return 1; + return 0; +} --- 2.3/ipc/msg.c Tue Nov 2 16:14:34 1999 +++ build-2.3/ipc/msg.c Fri Nov 5 23:53:19 1999 @@ -21,10 +21,14 @@ #include <linux/init.h> #include <linux/proc_fs.h> #include <linux/list.h> - #include <asm/uaccess.h> +#include "util.h" + +/* sysctl: */ +int msg_ctlmax = MSGMAX; +int msg_ctlmnb = MSGMNB; +int msg_ctlmni = MSGMNI; -#define USHRT_MAX 0xffff /* one ms_receiver structure for each sleeping receiver */ struct msg_receiver { struct list_head r_list; @@ -37,14 +41,21 @@ struct msg_msg* volatile r_msg; }; +struct msg_msgseg { + struct msg_msgseg* next; + /* the next part of the message follows immediately */ +}; /* one msg_msg structure for each message */ struct msg_msg { struct list_head m_list; long m_type; int m_ts; /* message text size */ + struct msg_msgseg* next; /* the actual message follows immediately */ }; +#define DATALEN_MSG (PAGE_SIZE-sizeof(struct msg_msg)) +#define DATALEN_SEG (PAGE_SIZE-sizeof(struct msg_msgseg)) /* one msq_queue structure for each present queue on the system */ struct msg_queue { @@ -63,110 +74,160 @@ wait_queue_head_t q_rwait; }; -/* one msq_array structure for each possible queue on the system */ -struct msg_array { - spinlock_t lock; - struct msg_queue* q; -}; - #define SEARCH_ANY 1 #define SEARCH_EQUAL 2 #define SEARCH_NOTEQUAL 3 #define SEARCH_LESSEQUAL 4 -static DECLARE_MUTEX(msg_lock); -static struct msg_array msg_que[MSGMNI]; - -static unsigned short msg_seq = 0; -static int msg_used_queues = 0; -static int msg_max_id = -1; - static atomic_t msg_bytes = ATOMIC_INIT(0); static atomic_t msg_hdrs = ATOMIC_INIT(0); +static struct ipc_ids msg_ids; + +#define msg_lock(id) ((struct msg_queue*)ipc_lock(&msg_ids,id)) +#define msg_unlock(id) ipc_unlock(&msg_ids,id) +#define msg_rmid(id) ((struct msg_queue*)ipc_rmid(&msg_ids,id)) +#define msg_checkid(msq, msgid) \ + ipc_checkid(&msg_ids,&msq->q_perm,msgid) +#define msg_buildid(id, seq) \ + ipc_buildid(&msg_ids, id, seq) + static void freeque (int id); static int newque (key_t key, int msgflg); -static int findkey (key_t key); #ifdef CONFIG_PROC_FS static int sysvipc_msg_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data); #endif -/* implemented in ipc/util.c, thread-safe */ -extern int ipcperms (struct ipc_perm *ipcp, short msgflg); - void __init msg_init (void) { - int id; + ipc_init_ids(&msg_ids,msg_ctlmni); - for (id = 0; id < MSGMNI; id++) { - msg_que[id].lock = SPIN_LOCK_UNLOCKED; - msg_que[id].q = NULL; - } #ifdef CONFIG_PROC_FS create_proc_read_entry("sysvipc/msg", 0, 0, sysvipc_msg_read_proc, NULL); #endif } -static int findkey (key_t key) -{ - int id; - struct msg_queue *msq; - - for (id = 0; id <= msg_max_id; id++) { - msq = msg_que[id].q; - if(msq == NULL) - continue; - if (key == msq->q_perm.key) - return id; - } - return -1; -} - static int newque (key_t key, int msgflg) { int id; struct msg_queue *msq; - struct ipc_perm *ipcp; - - for (id = 0; id < MSGMNI; id++) { - if (msg_que[id].q == NULL) - break; - } - if(id == MSGMNI) - return -ENOSPC; msq = (struct msg_queue *) kmalloc (sizeof (*msq), GFP_KERNEL); if (!msq) return -ENOMEM; - ipcp = &msq->q_perm; - ipcp->mode = (msgflg & S_IRWXUGO); - ipcp->key = key; - ipcp->cuid = ipcp->uid = current->euid; - ipcp->gid = ipcp->cgid = current->egid; - - /* ipcp->seq*MSGMNI must be a positive integer. - * this limits MSGMNI to 32768 - */ - ipcp->seq = msg_seq++; + ipc_grow_ids(&msg_ids,msg_ctlmni); + id = ipc_addid(&msg_ids, &msq->q_perm); + if(id == -1) { + kfree(msq); + return -ENOSPC; + } + msq->q_perm.mode = (msgflg & S_IRWXUGO); + msq->q_perm.key = key; msq->q_stime = msq->q_rtime = 0; msq->q_ctime = CURRENT_TIME; msq->q_cbytes = msq->q_qnum = 0; - msq->q_qbytes = MSGMNB; + msq->q_qbytes = msg_ctlmnb; msq->q_lspid = msq->q_lrpid = 0; INIT_LIST_HEAD(&msq->q_messages); INIT_LIST_HEAD(&msq->q_receivers); init_waitqueue_head(&msq->q_rwait); - if (id > msg_max_id) - msg_max_id = id; - spin_lock(&msg_que[id].lock); - msg_que[id].q = msq; - spin_unlock(&msg_que[id].lock); - msg_used_queues++; + msg_unlock(id); - return (int)msq->q_perm.seq * MSGMNI + id; + return msg_buildid(id,msq->q_perm.seq); +} + +static void free_msg(struct msg_msg* msg) +{ + struct msg_msgseg* seg; + seg = msg->next; + kfree(msg); + while(seg != NULL) { + struct msg_msgseg* tmp = seg->next; + kfree(seg); + seg = tmp; + } +} + +static struct msg_msg* load_msg(void* src, int len) +{ + struct msg_msg* msg; + struct msg_msgseg** pseg; + int err; + int alen; + + alen = len; + if(alen > DATALEN_MSG) + alen = DATALEN_MSG; + + msg = (struct msg_msg *) kmalloc (sizeof(*msg) + alen, GFP_KERNEL); + if(msg==NULL) + return ERR_PTR(-ENOMEM); + + msg->next = NULL; + + if (copy_from_user(msg+1, src, alen)) { + err = -EFAULT; + goto out_err; + } + + len -= alen; + src = ((char*)src)+alen; + pseg = &msg->next; + while(len > 0) { + struct msg_msgseg* seg; + alen = len; + if(alen > DATALEN_SEG) + alen = DATALEN_SEG; + seg = (struct msg_msgseg *) kmalloc (sizeof(*seg) + alen, GFP_KERNEL); + if(seg==NULL) { + err=-ENOMEM; + goto out_err; + } + *pseg = seg; + seg->next = NULL; + if(copy_from_user (seg+1, src, alen)) { + err = -EFAULT; + goto out_err; + } + pseg = &seg->next; + len -= alen; + src = ((char*)src)+alen; + } + return msg; + +out_err: + free_msg(msg); + return ERR_PTR(err); +} + +static int store_msg(void* dest, struct msg_msg* msg, int len) +{ + int alen; + struct msg_msgseg *seg; + + alen = len; + if(alen > DATALEN_MSG) + alen = DATALEN_MSG; + if(copy_to_user (dest, msg+1, alen)) + return -1; + + len -= alen; + dest = ((char*)dest)+alen; + seg = msg->next; + while(len > 0) { + alen = len; + if(alen > DATALEN_SEG) + alen = DATALEN_SEG; + if(copy_to_user (dest, seg+1, alen)) + return -1; + len -= alen; + dest = ((char*)dest)+alen; + seg=seg->next; + } + return 0; } static void expunge_all(struct msg_queue* msq, int res) @@ -189,48 +250,39 @@ struct msg_queue *msq; struct list_head *tmp; - msq=msg_que[id].q; - msg_que[id].q = NULL; - if (id == msg_max_id) { - while ((msg_que[msg_max_id].q == NULL)) { - if(msg_max_id--== 0) - break; - } - } - msg_used_queues--; + msq = msg_rmid(id); expunge_all(msq,-EIDRM); while(waitqueue_active(&msq->q_rwait)) { wake_up(&msq->q_rwait); - spin_unlock(&msg_que[id].lock); + msg_unlock(id); current->policy |= SCHED_YIELD; schedule(); - spin_lock(&msg_que[id].lock); + msg_lock(id); } - spin_unlock(&msg_que[id].lock); + msg_unlock(id); tmp = msq->q_messages.next; while(tmp != &msq->q_messages) { struct msg_msg* msg = list_entry(tmp,struct msg_msg,m_list); tmp = tmp->next; atomic_dec(&msg_hdrs); - kfree(msg); + free_msg(msg); } atomic_sub(msq->q_cbytes, &msg_bytes); kfree(msq); } - asmlinkage long sys_msgget (key_t key, int msgflg) { int id, ret = -EPERM; struct msg_queue *msq; - down(&msg_lock); + down(&msg_ids.sem); if (key == IPC_PRIVATE) ret = newque(key, msgflg); - else if ((id = findkey (key)) == -1) { /* key not used */ + else if ((id = ipc_findkey(&msg_ids, key)) == -1) { /* key not used */ if (!(msgflg & IPC_CREAT)) ret = -ENOENT; else @@ -238,31 +290,35 @@ } else if (msgflg & IPC_CREAT && msgflg & IPC_EXCL) { ret = -EEXIST; } else { - msq = msg_que[id].q; + msq = msg_lock(id); + if(msq==NULL) + BUG(); if (ipcperms(&msq->q_perm, msgflg)) ret = -EACCES; else - ret = (unsigned int) msq->q_perm.seq * MSGMNI + id; + ret = msg_buildid(id, msq->q_perm.seq); + msg_unlock(id); } - up(&msg_lock); + up(&msg_ids.sem); return ret; } asmlinkage long sys_msgctl (int msqid, int cmd, struct msqid_ds *buf) { - int id, err; + int err; struct msg_queue *msq; struct msqid_ds tbuf; struct ipc_perm *ipcp; if (msqid < 0 || cmd < 0) return -EINVAL; - id = msqid % MSGMNI; + switch (cmd) { case IPC_INFO: case MSG_INFO: { struct msginfo msginfo; + int max_id; if (!buf) return -EFAULT; /* We must not return kernel stack data. @@ -270,23 +326,25 @@ * to set all member fields. */ memset(&msginfo,0,sizeof(msginfo)); - msginfo.msgmni = MSGMNI; - msginfo.msgmax = MSGMAX; - msginfo.msgmnb = MSGMNB; + msginfo.msgmni = msg_ctlmni; + msginfo.msgmax = msg_ctlmax; + msginfo.msgmnb = msg_ctlmnb; msginfo.msgmap = MSGMAP; msginfo.msgpool = MSGPOOL; msginfo.msgtql = MSGTQL; msginfo.msgssz = MSGSSZ; msginfo.msgseg = MSGSEG; + down(&msg_ids.sem); if (cmd == MSG_INFO) { - msginfo.msgpool = msg_used_queues; + msginfo.msgpool = msg_ids.in_use; msginfo.msgmap = atomic_read(&msg_hdrs); msginfo.msgtql = atomic_read(&msg_bytes); } - + max_id = msg_ids.max_id; + up(&msg_ids.sem); if (copy_to_user (buf, &msginfo, sizeof(struct msginfo))) return -EFAULT; - return (msg_max_id < 0) ? 0: msg_max_id; + return (max_id < 0) ? 0: max_id; } case MSG_STAT: case IPC_STAT: @@ -297,16 +355,15 @@ if(cmd == MSG_STAT && msqid > MSGMNI) return -EINVAL; - spin_lock(&msg_que[id].lock); - msq = msg_que[id].q; + msq = msg_lock(msqid); err = -EINVAL; if (msq == NULL) goto out_unlock; if(cmd == MSG_STAT) { - success_return = (unsigned int) msq->q_perm.seq * MSGMNI + msqid; + success_return = msg_buildid(msqid, msq->q_perm.seq); } else { err = -EIDRM; - if (msq->q_perm.seq != (unsigned int) msqid / MSGMNI) + if (msg_checkid(msq,msqid)) goto out_unlock; success_return = 0; } @@ -339,7 +396,7 @@ tbuf.msg_lspid = msq->q_lspid; tbuf.msg_lrpid = msq->q_lrpid; - spin_unlock(&msg_que[id].lock); + msg_unlock(msqid); if (copy_to_user (buf, &tbuf, sizeof(*buf))) return -EFAULT; return success_return; @@ -356,14 +413,13 @@ return -EINVAL; } - down(&msg_lock); - spin_lock(&msg_que[id].lock); - msq = msg_que[id].q; + down(&msg_ids.sem); + msq = msg_lock(msqid); err = -EINVAL; if (msq == NULL) goto out_unlock_up; err = -EIDRM; - if (msq->q_perm.seq != (unsigned int) msqid / MSGMNI) + if (msg_checkid(msq,msqid)) goto out_unlock_up; ipcp = &msq->q_perm; @@ -381,7 +437,7 @@ newqbytes = tbuf.msg_lqbytes; else newqbytes = tbuf.msg_qbytes; - if (newqbytes > MSGMNB && !capable(CAP_SYS_RESOURCE)) + if (newqbytes > msg_ctlmnb && !capable(CAP_SYS_RESOURCE)) goto out_unlock_up; msq->q_qbytes = newqbytes; @@ -398,7 +454,7 @@ * due to a larger queue size. */ wake_up(&msq->q_rwait); - spin_unlock(&msg_que[id].lock); + msg_unlock(msqid); break; } case IPC_RMID: @@ -406,18 +462,18 @@ if (current->euid != ipcp->cuid && current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN)) goto out_unlock; - freeque (id); + freeque (msqid); break; } err = 0; out_up: - up(&msg_lock); + up(&msg_ids.sem); return err; out_unlock_up: - spin_unlock(&msg_que[id].lock); + msg_unlock(msqid); goto out_up; out_unlock: - spin_unlock(&msg_que[id].lock); + msg_unlock(msqid); return err; } @@ -471,35 +527,28 @@ asmlinkage long sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg) { - int id; struct msg_queue *msq; struct msg_msg *msg; long mtype; int err; - if (msgsz > MSGMAX || (long) msgsz < 0 || msqid < 0) + if (msgsz > msg_ctlmax || (long) msgsz < 0 || msqid < 0) return -EINVAL; if (get_user(mtype, &msgp->mtype)) return -EFAULT; if (mtype < 1) return -EINVAL; - msg = (struct msg_msg *) kmalloc (sizeof(*msg) + msgsz, GFP_KERNEL); - if(msg==NULL) - return -ENOMEM; + msg = load_msg(msgp->mtext, msgsz); + if(IS_ERR(msg)) + return PTR_ERR(msg); - if (copy_from_user(msg+1, msgp->mtext, msgsz)) { - kfree(msg); - return -EFAULT; - } msg->m_type = mtype; msg->m_ts = msgsz; - id = (unsigned int) msqid % MSGMNI; - spin_lock(&msg_que[id].lock); + msq = msg_lock(msqid); err= -EINVAL; retry: - msq = msg_que[id].q; if (msq == NULL) goto out_free; @@ -520,17 +569,17 @@ } current->state = TASK_INTERRUPTIBLE; add_wait_queue(&msq->q_rwait,&wait); - spin_unlock(&msg_que[id].lock); + msg_unlock(msqid); schedule(); current->state= TASK_RUNNING; remove_wait_queue(&msq->q_rwait,&wait); if (signal_pending(current)) { - kfree(msg); + free_msg(msg); return -EINTR; } - spin_lock(&msg_que[id].lock); + msq = msg_lock(msqid); err = -EIDRM; goto retry; } @@ -550,9 +599,9 @@ msq->q_stime = CURRENT_TIME; out_free: + msg_unlock(msqid); if(msg!=NULL) - kfree(msg); - spin_unlock(&msg_que[id].lock); + free_msg(msg); return err; } @@ -582,7 +631,6 @@ struct msg_receiver msr_d; struct list_head* tmp; struct msg_msg* msg, *found_msg; - int id; int err; int mode; @@ -590,10 +638,8 @@ return -EINVAL; mode = convert_mode(&msgtyp,msgflg); - id = (unsigned int) msqid % MSGMNI; - spin_lock(&msg_que[id].lock); + msq = msg_lock(msqid); retry: - msq = msg_que[id].q; err=-EINVAL; if (msq == NULL) goto out_unlock; @@ -633,15 +679,14 @@ if(waitqueue_active(&msq->q_rwait)) wake_up(&msq->q_rwait); out_success_unlock: - spin_unlock(&msg_que[id].lock); + msg_unlock(msqid); out_success: msgsz = (msgsz > msg->m_ts) ? msg->m_ts : msgsz; if (put_user (msg->m_type, &msgp->mtype) || - copy_to_user (msgp->mtext, msg+1, msgsz)) - { + store_msg(msgp->mtext, msg, msgsz)) { msgsz = -EFAULT; } - kfree(msg); + free_msg(msg); return msgsz; } else { @@ -657,12 +702,13 @@ msr_d.r_msgtype = msgtyp; msr_d.r_mode = mode; if(msgflg & MSG_NOERROR) - msr_d.r_maxsize = MSGMAX; + msr_d.r_maxsize = INT_MAX; else msr_d.r_maxsize = msgsz; msr_d.r_msg = ERR_PTR(-EAGAIN); current->state = TASK_INTERRUPTIBLE; - spin_unlock(&msg_que[id].lock); + msg_unlock(msqid); + schedule(); current->state = TASK_RUNNING; @@ -670,7 +716,7 @@ if(!IS_ERR(msg)) goto out_success; - spin_lock(&msg_que[id].lock); + msg_lock(msqid); msg = (struct msg_msg*)msr_d.r_msg; if(!IS_ERR(msg)) { /* our message arived while we waited for @@ -688,7 +734,7 @@ } } out_unlock: - spin_unlock(&msg_que[id].lock); + msg_unlock(msqid); return err; } @@ -699,43 +745,42 @@ off_t begin = 0; int i, len = 0; - down(&msg_lock); + down(&msg_ids.sem); len += sprintf(buffer, " key msqid perms cbytes qnum lspid lrpid uid gid cuid cgid stime rtime ctime\n"); - for(i = 0; i <= msg_max_id; i++) { - spin_lock(&msg_que[i].lock); - if(msg_que[i].q != NULL) { + for(i = 0; i <= msg_ids.max_id; i++) { + struct msg_queue * msq; + msq = msg_lock(i); + if(msq != NULL) { len += sprintf(buffer + len, "%10d %10d %4o %5u %5u %5u %5u %5u %5u %5u %5u %10lu %10lu %10lu\n", - msg_que[i].q->q_perm.key, - msg_que[i].q->q_perm.seq * MSGMNI + i, - msg_que[i].q->q_perm.mode, - msg_que[i].q->q_cbytes, - msg_que[i].q->q_qnum, - msg_que[i].q->q_lspid, - msg_que[i].q->q_lrpid, - msg_que[i].q->q_perm.uid, - msg_que[i].q->q_perm.gid, - msg_que[i].q->q_perm.cuid, - msg_que[i].q->q_perm.cgid, - msg_que[i].q->q_stime, - msg_que[i].q->q_rtime, - msg_que[i].q->q_ctime); - spin_unlock(&msg_que[i].lock); - - pos += len; - if(pos < offset) { - len = 0; - begin = pos; - } - if(pos > offset + length) - goto done; - } else { - spin_unlock(&msg_que[i].lock); + msq->q_perm.key, + msg_buildid(i,msq->q_perm.seq), + msq->q_perm.mode, + msq->q_cbytes, + msq->q_qnum, + msq->q_lspid, + msq->q_lrpid, + msq->q_perm.uid, + msq->q_perm.gid, + msq->q_perm.cuid, + msq->q_perm.cgid, + msq->q_stime, + msq->q_rtime, + msq->q_ctime); + } + msg_unlock(i); + + pos += len; + if(pos < offset) { + len = 0; + begin = pos; } + if(pos > offset + length) + goto done; } *eof = 1; done: - up(&msg_lock); + up(&msg_ids.sem); *start = buffer + (offset - begin); len -= (offset - begin); if(len > length) --- 2.3/include/linux/sem.h Tue Nov 2 16:14:33 1999 +++ build-2.3/include/linux/sem.h Fri Nov 5 23:53:19 1999 @@ -60,10 +60,10 @@ int semaem; }; -#define SEMMNI 128 /* <= 32767 max # of semaphore identifiers */ -#define SEMMSL 250 /* <= 512 max num of semaphores per id */ -#define SEMMNS (SEMMNI*SEMMSL) /* <= MAX_INT max # of semaphores in system */ -#define SEMOPM 32 /* <= 160 max num of ops per semop call */ +#define SEMMNI 128 /* <= IPCMNI max # of semaphore identifiers */ +#define SEMMSL 250 /* <= 60 000 max num of semaphores per id */ +#define SEMMNS (SEMMNI*SEMMSL) /* <= INT_MAX max # of semaphores in system */ +#define SEMOPM 32 /* <= 20 000 max num of ops per semop call */ #define SEMVMX 32767 /* <= 32767 semaphore maximum value */ /* unused */ --- 2.3/include/linux/msg.h Sat Oct 9 22:51:29 1999 +++ build-2.3/include/linux/msg.h Fri Nov 5 23:53:19 1999 @@ -45,9 +45,9 @@ unsigned short msgseg; }; -#define MSGMNI 128 /* <= 32768 */ /* max # of msg queue identifiers */ -#define MSGMAX 4056 /* <= 4056 (?)*/ /* max size of message (bytes) */ -#define MSGMNB 16384 /* <= MAX_INT */ /* default max size of a message queue */ +#define MSGMNI 128 /* <= IPCMNI */ /* max # of msg queue identifiers */ +#define MSGMAX 8192 /* <= INT_MAX */ /* max size of message (bytes) */ +#define MSGMNB 16384 /* <= INT_MAX */ /* default max size of a message queue */ /* unused */ #define MSGPOOL (MSGMNI*MSGMNB/1024) /* size in kilobytes of message pool */ --- 2.3/include/linux/ipc.h Tue Nov 2 16:14:33 1999 +++ build-2.3/include/linux/ipc.h Fri Nov 5 23:53:19 1999 @@ -42,6 +42,8 @@ #define IPC_UNUSED ((void *) -1) #define IPC_NOID ((void *) -2) /* being allocated/destroyed */ +#define IPCMNI 32768 /* <= MAX_INT limit for ipc arrays (including sysctl changes) */ + #endif /* __KERNEL__ */ #endif /* _LINUX_IPC_H */ --- 2.3/include/linux/sysctl.h Fri Nov 5 16:35:34 1999 +++ build-2.3/include/linux/sysctl.h Fri Nov 5 23:53:19 1999 @@ -103,7 +103,9 @@ KERN_MSGPOOL=37, /* int: Maximum system message pool size */ KERN_SYSRQ=38, /* int: Sysreq enable */ KERN_MAX_THREADS=39, /* int: Maximum nr of threads in the system */ - KERN_RANDOM=40 /* Random driver */ + KERN_RANDOM=40, /* Random driver */ + KERN_MSGMNI=41, /* int: msg queue identifiers */ + KERN_SEM=42 /* int: sysv semaphore limits */ }; --- 2.3/kernel/sysctl.c Fri Nov 5 16:35:35 1999 +++ build-2.3/kernel/sysctl.c Fri Nov 5 23:53:19 1999 @@ -50,6 +50,10 @@ #endif #ifdef CONFIG_SYSVIPC extern size_t shm_prm[]; +extern int msg_ctlmax; +extern int msg_ctlmnb; +extern int msg_ctlmni; +extern int sem_ctls[]; #endif #ifdef __sparc__ @@ -215,6 +219,14 @@ #ifdef CONFIG_SYSVIPC {KERN_SHMMAX, "shmmax", &shm_prm, 3*sizeof (size_t), 0644, NULL, &proc_doulongvec_minmax}, + {KERN_MSGMAX, "msgmax", &msg_ctlmax, sizeof (int), + 0644, NULL, &proc_dointvec}, + {KERN_MSGMNI, "msgmni", &msg_ctlmni, sizeof (int), + 0644, NULL, &proc_dointvec}, + {KERN_MSGMNB, "msgmnb", &msg_ctlmnb, sizeof (int), + 0644, NULL, &proc_dointvec}, + {KERN_SEM, "sem", &sem_ctls, 4*sizeof (int), + 0644, NULL, &proc_dointvec}, #endif #ifdef CONFIG_MAGIC_SYSRQ {KERN_SYSRQ, "sysrq", &sysrq_enabled, sizeof (int), >>>>>>>>>>>>>>
- 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/