File: /usr/src/linux/ipc/sem.c

1     /*
2      * linux/ipc/sem.c
3      * Copyright (C) 1992 Krishna Balasubramanian
4      * Copyright (C) 1995 Eric Schenk, Bruno Haible
5      *
6      * IMPLEMENTATION NOTES ON CODE REWRITE (Eric Schenk, January 1995):
7      * This code underwent a massive rewrite in order to solve some problems
8      * with the original code. In particular the original code failed to
9      * wake up processes that were waiting for semval to go to 0 if the
10      * value went to 0 and was then incremented rapidly enough. In solving
11      * this problem I have also modified the implementation so that it
12      * processes pending operations in a FIFO manner, thus give a guarantee
13      * that processes waiting for a lock on the semaphore won't starve
14      * unless another locking process fails to unlock.
15      * In addition the following two changes in behavior have been introduced:
16      * - The original implementation of semop returned the value
17      *   last semaphore element examined on success. This does not
18      *   match the manual page specifications, and effectively
19      *   allows the user to read the semaphore even if they do not
20      *   have read permissions. The implementation now returns 0
21      *   on success as stated in the manual page.
22      * - There is some confusion over whether the set of undo adjustments
23      *   to be performed at exit should be done in an atomic manner.
24      *   That is, if we are attempting to decrement the semval should we queue
25      *   up and wait until we can do so legally?
26      *   The original implementation attempted to do this.
27      *   The current implementation does not do so. This is because I don't
28      *   think it is the right thing (TM) to do, and because I couldn't
29      *   see a clean way to get the old behavior with the new design.
30      *   The POSIX standard and SVID should be consulted to determine
31      *   what behavior is mandated.
32      *
33      * Further notes on refinement (Christoph Rohland, December 1998):
34      * - The POSIX standard says, that the undo adjustments simply should
35      *   redo. So the current implementation is o.K.
36      * - The previous code had two flaws:
37      *   1) It actively gave the semaphore to the next waiting process
38      *      sleeping on the semaphore. Since this process did not have the
39      *      cpu this led to many unnecessary context switches and bad
40      *      performance. Now we only check which process should be able to
41      *      get the semaphore and if this process wants to reduce some
42      *      semaphore value we simply wake it up without doing the
43      *      operation. So it has to try to get it later. Thus e.g. the
44      *      running process may reacquire the semaphore during the current
45      *      time slice. If it only waits for zero or increases the semaphore,
46      *      we do the operation in advance and wake it up.
47      *   2) It did not wake up all zero waiting processes. We try to do
48      *      better but only get the semops right which only wait for zero or
49      *      increase. If there are decrement operations in the operations
50      *      array we do the same as before.
51      *
52      * /proc/sysvipc/sem support (c) 1999 Dragos Acostachioaie <dragos@iname.com>
53      *
54      * SMP-threaded, sysctl's added
55      * (c) 1999 Manfred Spraul <manfreds@colorfullife.com>
56      */
57     
58     #include <linux/config.h>
59     #include <linux/slab.h>
60     #include <linux/spinlock.h>
61     #include <linux/init.h>
62     #include <linux/proc_fs.h>
63     #include <asm/uaccess.h>
64     #include "util.h"
65     
66     
67     #define sem_lock(id)	((struct sem_array*)ipc_lock(&sem_ids,id))
68     #define sem_unlock(id)	ipc_unlock(&sem_ids,id)
69     #define sem_rmid(id)	((struct sem_array*)ipc_rmid(&sem_ids,id))
70     #define sem_checkid(sma, semid)	\
71     	ipc_checkid(&sem_ids,&sma->sem_perm,semid)
72     #define sem_buildid(id, seq) \
73     	ipc_buildid(&sem_ids, id, seq)
74     static struct ipc_ids sem_ids;
75     
76     static int newary (key_t, int, int);
77     static void freeary (int id);
78     #ifdef CONFIG_PROC_FS
79     static int sysvipc_sem_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data);
80     #endif
81     
82     #define SEMMSL_FAST	256 /* 512 bytes on stack */
83     #define SEMOPM_FAST	64  /* ~ 372 bytes on stack */
84     
85     /*
86      * linked list protection:
87      *	sem_undo.id_next,
88      *	sem_array.sem_pending{,last},
89      *	sem_array.sem_undo: sem_lock() for read/write
90      *	sem_undo.proc_next: only "current" is allowed to read/write that field.
91      *	
92      */
93     
94     int sem_ctls[4] = {SEMMSL, SEMMNS, SEMOPM, SEMMNI};
95     #define sc_semmsl	(sem_ctls[0])
96     #define sc_semmns	(sem_ctls[1])
97     #define sc_semopm	(sem_ctls[2])
98     #define sc_semmni	(sem_ctls[3])
99     
100     static int used_sems;
101     
102     void __init sem_init (void)
103     {
104     	used_sems = 0;
105     	ipc_init_ids(&sem_ids,sc_semmni);
106     
107     #ifdef CONFIG_PROC_FS
108     	create_proc_read_entry("sysvipc/sem", 0, 0, sysvipc_sem_read_proc, NULL);
109     #endif
110     }
111     
112     static int newary (key_t key, int nsems, int semflg)
113     {
114     	int id;
115     	struct sem_array *sma;
116     	int size;
117     
118     	if (!nsems)
119     		return -EINVAL;
120     	if (used_sems + nsems > sc_semmns)
121     		return -ENOSPC;
122     
123     	size = sizeof (*sma) + nsems * sizeof (struct sem);
124     	sma = (struct sem_array *) ipc_alloc(size);
125     	if (!sma) {
126     		return -ENOMEM;
127     	}
128     	memset (sma, 0, size);
129     	id = ipc_addid(&sem_ids, &sma->sem_perm, sc_semmni);
130     	if(id == -1) {
131     		ipc_free(sma, size);
132     		return -ENOSPC;
133     	}
134     	used_sems += nsems;
135     
136     	sma->sem_perm.mode = (semflg & S_IRWXUGO);
137     	sma->sem_perm.key = key;
138     
139     	sma->sem_base = (struct sem *) &sma[1];
140     	/* sma->sem_pending = NULL; */
141     	sma->sem_pending_last = &sma->sem_pending;
142     	/* sma->undo = NULL; */
143     	sma->sem_nsems = nsems;
144     	sma->sem_ctime = CURRENT_TIME;
145     	sem_unlock(id);
146     
147     	return sem_buildid(id, sma->sem_perm.seq);
148     }
149     
150     asmlinkage long sys_semget (key_t key, int nsems, int semflg)
151     {
152     	int id, err = -EINVAL;
153     	struct sem_array *sma;
154     
155     	if (nsems < 0 || nsems > sc_semmsl)
156     		return -EINVAL;
157     	down(&sem_ids.sem);
158     	
159     	if (key == IPC_PRIVATE) {
160     		err = newary(key, nsems, semflg);
161     	} else if ((id = ipc_findkey(&sem_ids, key)) == -1) {  /* key not used */
162     		if (!(semflg & IPC_CREAT))
163     			err = -ENOENT;
164     		else
165     			err = newary(key, nsems, semflg);
166     	} else if (semflg & IPC_CREAT && semflg & IPC_EXCL) {
167     		err = -EEXIST;
168     	} else {
169     		sma = sem_lock(id);
170     		if(sma==NULL)
171     			BUG();
172     		if (nsems > sma->sem_nsems)
173     			err = -EINVAL;
174     		else if (ipcperms(&sma->sem_perm, semflg))
175     			err = -EACCES;
176     		else
177     			err = sem_buildid(id, sma->sem_perm.seq);
178     		sem_unlock(id);
179     	}
180     
181     	up(&sem_ids.sem);
182     	return err;
183     }
184     
185     /* doesn't acquire the sem_lock on error! */
186     static int sem_revalidate(int semid, struct sem_array* sma, int nsems, short flg)
187     {
188     	struct sem_array* smanew;
189     
190     	smanew = sem_lock(semid);
191     	if(smanew==NULL)
192     		return -EIDRM;
193     	if(smanew != sma || sem_checkid(sma,semid) || sma->sem_nsems != nsems) {
194     		sem_unlock(semid);
195     		return -EIDRM;
196     	}
197     
198     	if (ipcperms(&sma->sem_perm, flg)) {
199     		sem_unlock(semid);
200     		return -EACCES;
201     	}
202     	return 0;
203     }
204     /* Manage the doubly linked list sma->sem_pending as a FIFO:
205      * insert new queue elements at the tail sma->sem_pending_last.
206      */
207     static inline void append_to_queue (struct sem_array * sma,
208     				    struct sem_queue * q)
209     {
210     	*(q->prev = sma->sem_pending_last) = q;
211     	*(sma->sem_pending_last = &q->next) = NULL;
212     }
213     
214     static inline void prepend_to_queue (struct sem_array * sma,
215     				     struct sem_queue * q)
216     {
217     	q->next = sma->sem_pending;
218     	*(q->prev = &sma->sem_pending) = q;
219     	if (q->next)
220     		q->next->prev = &q->next;
221     	else /* sma->sem_pending_last == &sma->sem_pending */
222     		sma->sem_pending_last = &q->next;
223     }
224     
225     static inline void remove_from_queue (struct sem_array * sma,
226     				      struct sem_queue * q)
227     {
228     	*(q->prev) = q->next;
229     	if (q->next)
230     		q->next->prev = q->prev;
231     	else /* sma->sem_pending_last == &q->next */
232     		sma->sem_pending_last = q->prev;
233     	q->prev = NULL; /* mark as removed */
234     }
235     
236     /*
237      * Determine whether a sequence of semaphore operations would succeed
238      * all at once. Return 0 if yes, 1 if need to sleep, else return error code.
239      */
240     
241     static int try_atomic_semop (struct sem_array * sma, struct sembuf * sops,
242     			     int nsops, struct sem_undo *un, int pid,
243     			     int do_undo)
244     {
245     	int result, sem_op;
246     	struct sembuf *sop;
247     	struct sem * curr;
248     
249     	for (sop = sops; sop < sops + nsops; sop++) {
250     		curr = sma->sem_base + sop->sem_num;
251     		sem_op = sop->sem_op;
252     
253     		if (!sem_op && curr->semval)
254     			goto would_block;
255     
256     		curr->sempid = (curr->sempid << 16) | pid;
257     		curr->semval += sem_op;
258     		if (sop->sem_flg & SEM_UNDO)
259     			un->semadj[sop->sem_num] -= sem_op;
260     
261     		if (curr->semval < 0)
262     			goto would_block;
263     		if (curr->semval > SEMVMX)
264     			goto out_of_range;
265     	}
266     
267     	if (do_undo)
268     	{
269     		sop--;
270     		result = 0;
271     		goto undo;
272     	}
273     
274     	sma->sem_otime = CURRENT_TIME;
275     	return 0;
276     
277     out_of_range:
278     	result = -ERANGE;
279     	goto undo;
280     
281     would_block:
282     	if (sop->sem_flg & IPC_NOWAIT)
283     		result = -EAGAIN;
284     	else
285     		result = 1;
286     
287     undo:
288     	while (sop >= sops) {
289     		curr = sma->sem_base + sop->sem_num;
290     		curr->semval -= sop->sem_op;
291     		curr->sempid >>= 16;
292     
293     		if (sop->sem_flg & SEM_UNDO)
294     			un->semadj[sop->sem_num] += sop->sem_op;
295     		sop--;
296     	}
297     
298     	return result;
299     }
300     
301     /* Go through the pending queue for the indicated semaphore
302      * looking for tasks that can be completed.
303      */
304     static void update_queue (struct sem_array * sma)
305     {
306     	int error;
307     	struct sem_queue * q;
308     
309     	for (q = sma->sem_pending; q; q = q->next) {
310     			
311     		if (q->status == 1)
312     			continue;	/* this one was woken up before */
313     
314     		error = try_atomic_semop(sma, q->sops, q->nsops,
315     					 q->undo, q->pid, q->alter);
316     
317     		/* Does q->sleeper still need to sleep? */
318     		if (error <= 0) {
319     				/* Found one, wake it up */
320     			wake_up_process(q->sleeper);
321     			if (error == 0 && q->alter) {
322     				/* if q-> alter let it self try */
323     				q->status = 1;
324     				return;
325     			}
326     			q->status = error;
327     			remove_from_queue(sma,q);
328     		}
329     	}
330     }
331     
332     /* The following counts are associated to each semaphore:
333      *   semncnt        number of tasks waiting on semval being nonzero
334      *   semzcnt        number of tasks waiting on semval being zero
335      * This model assumes that a task waits on exactly one semaphore.
336      * Since semaphore operations are to be performed atomically, tasks actually
337      * wait on a whole sequence of semaphores simultaneously.
338      * The counts we return here are a rough approximation, but still
339      * warrant that semncnt+semzcnt>0 if the task is on the pending queue.
340      */
341     static int count_semncnt (struct sem_array * sma, ushort semnum)
342     {
343     	int semncnt;
344     	struct sem_queue * q;
345     
346     	semncnt = 0;
347     	for (q = sma->sem_pending; q; q = q->next) {
348     		struct sembuf * sops = q->sops;
349     		int nsops = q->nsops;
350     		int i;
351     		for (i = 0; i < nsops; i++)
352     			if (sops[i].sem_num == semnum
353     			    && (sops[i].sem_op < 0)
354     			    && !(sops[i].sem_flg & IPC_NOWAIT))
355     				semncnt++;
356     	}
357     	return semncnt;
358     }
359     static int count_semzcnt (struct sem_array * sma, ushort semnum)
360     {
361     	int semzcnt;
362     	struct sem_queue * q;
363     
364     	semzcnt = 0;
365     	for (q = sma->sem_pending; q; q = q->next) {
366     		struct sembuf * sops = q->sops;
367     		int nsops = q->nsops;
368     		int i;
369     		for (i = 0; i < nsops; i++)
370     			if (sops[i].sem_num == semnum
371     			    && (sops[i].sem_op == 0)
372     			    && !(sops[i].sem_flg & IPC_NOWAIT))
373     				semzcnt++;
374     	}
375     	return semzcnt;
376     }
377     
378     /* Free a semaphore set. */
379     static void freeary (int id)
380     {
381     	struct sem_array *sma;
382     	struct sem_undo *un;
383     	struct sem_queue *q;
384     	int size;
385     
386     	sma = sem_rmid(id);
387     
388     	/* Invalidate the existing undo structures for this semaphore set.
389     	 * (They will be freed without any further action in sem_exit()
390     	 * or during the next semop.)
391     	 */
392     	for (un = sma->undo; un; un = un->id_next)
393     		un->semid = -1;
394     
395     	/* Wake up all pending processes and let them fail with EIDRM. */
396     	for (q = sma->sem_pending; q; q = q->next) {
397     		q->status = -EIDRM;
398     		q->prev = NULL;
399     		wake_up_process(q->sleeper); /* doesn't sleep */
400     	}
401     	sem_unlock(id);
402     
403     	used_sems -= sma->sem_nsems;
404     	size = sizeof (*sma) + sma->sem_nsems * sizeof (struct sem);
405     	ipc_free(sma, size);
406     }
407     
408     static unsigned long copy_semid_to_user(void *buf, struct semid64_ds *in, int version)
409     {
410     	switch(version) {
411     	case IPC_64:
412     		return copy_to_user(buf, in, sizeof(*in));
413     	case IPC_OLD:
414     	    {
415     		struct semid_ds out;
416     
417     		ipc64_perm_to_ipc_perm(&in->sem_perm, &out.sem_perm);
418     
419     		out.sem_otime	= in->sem_otime;
420     		out.sem_ctime	= in->sem_ctime;
421     		out.sem_nsems	= in->sem_nsems;
422     
423     		return copy_to_user(buf, &out, sizeof(out));
424     	    }
425     	default:
426     		return -EINVAL;
427     	}
428     }
429     
430     int semctl_nolock(int semid, int semnum, int cmd, int version, union semun arg)
431     {
432     	int err = -EINVAL;
433     
434     	switch(cmd) {
435     	case IPC_INFO:
436     	case SEM_INFO:
437     	{
438     		struct seminfo seminfo;
439     		int max_id;
440     
441     		memset(&seminfo,0,sizeof(seminfo));
442     		seminfo.semmni = sc_semmni;
443     		seminfo.semmns = sc_semmns;
444     		seminfo.semmsl = sc_semmsl;
445     		seminfo.semopm = sc_semopm;
446     		seminfo.semvmx = SEMVMX;
447     		seminfo.semmnu = SEMMNU;
448     		seminfo.semmap = SEMMAP;
449     		seminfo.semume = SEMUME;
450     		down(&sem_ids.sem);
451     		if (cmd == SEM_INFO) {
452     			seminfo.semusz = sem_ids.in_use;
453     			seminfo.semaem = used_sems;
454     		} else {
455     			seminfo.semusz = SEMUSZ;
456     			seminfo.semaem = SEMAEM;
457     		}
458     		max_id = sem_ids.max_id;
459     		up(&sem_ids.sem);
460     		if (copy_to_user (arg.__buf, &seminfo, sizeof(struct seminfo))) 
461     			return -EFAULT;
462     		return (max_id < 0) ? 0: max_id;
463     	}
464     	case SEM_STAT:
465     	{
466     		struct sem_array *sma;
467     		struct semid64_ds tbuf;
468     		int id;
469     
470     		if(semid >= sem_ids.size)
471     			return -EINVAL;
472     
473     		memset(&tbuf,0,sizeof(tbuf));
474     
475     		sma = sem_lock(semid);
476     		if(sma == NULL)
477     			return -EINVAL;
478     
479     		err = -EACCES;
480     		if (ipcperms (&sma->sem_perm, S_IRUGO))
481     			goto out_unlock;
482     		id = sem_buildid(semid, sma->sem_perm.seq);
483     
484     		kernel_to_ipc64_perm(&sma->sem_perm, &tbuf.sem_perm);
485     		tbuf.sem_otime  = sma->sem_otime;
486     		tbuf.sem_ctime  = sma->sem_ctime;
487     		tbuf.sem_nsems  = sma->sem_nsems;
488     		sem_unlock(semid);
489     		if (copy_semid_to_user (arg.buf, &tbuf, version))
490     			return -EFAULT;
491     		return id;
492     	}
493     	default:
494     		return -EINVAL;
495     	}
496     	return err;
497     out_unlock:
498     	sem_unlock(semid);
499     	return err;
500     }
501     
502     int semctl_main(int semid, int semnum, int cmd, int version, union semun arg)
503     {
504     	struct sem_array *sma;
505     	struct sem* curr;
506     	int err;
507     	ushort fast_sem_io[SEMMSL_FAST];
508     	ushort* sem_io = fast_sem_io;
509     	int nsems;
510     
511     	sma = sem_lock(semid);
512     	if(sma==NULL)
513     		return -EINVAL;
514     
515     	nsems = sma->sem_nsems;
516     
517     	err=-EIDRM;
518     	if (sem_checkid(sma,semid))
519     		goto out_unlock;
520     
521     	err = -EACCES;
522     	if (ipcperms (&sma->sem_perm, (cmd==SETVAL||cmd==SETALL)?S_IWUGO:S_IRUGO))
523     		goto out_unlock;
524     
525     	switch (cmd) {
526     	case GETALL:
527     	{
528     		ushort *array = arg.array;
529     		int i;
530     
531     		if(nsems > SEMMSL_FAST) {
532     			sem_unlock(semid);			
533     			sem_io = ipc_alloc(sizeof(ushort)*nsems);
534     			if(sem_io == NULL)
535     				return -ENOMEM;
536     			err = sem_revalidate(semid, sma, nsems, S_IRUGO);
537     			if(err)
538     				goto out_free;
539     		}
540     
541     		for (i = 0; i < sma->sem_nsems; i++)
542     			sem_io[i] = sma->sem_base[i].semval;
543     		sem_unlock(semid);
544     		err = 0;
545     		if(copy_to_user(array, sem_io, nsems*sizeof(ushort)))
546     			err = -EFAULT;
547     		goto out_free;
548     	}
549     	case SETALL:
550     	{
551     		int i;
552     		struct sem_undo *un;
553     
554     		sem_unlock(semid);
555     
556     		if(nsems > SEMMSL_FAST) {
557     			sem_io = ipc_alloc(sizeof(ushort)*nsems);
558     			if(sem_io == NULL)
559     				return -ENOMEM;
560     		}
561     
562     		if (copy_from_user (sem_io, arg.array, nsems*sizeof(ushort))) {
563     			err = -EFAULT;
564     			goto out_free;
565     		}
566     
567     		for (i = 0; i < nsems; i++) {
568     			if (sem_io[i] > SEMVMX) {
569     				err = -ERANGE;
570     				goto out_free;
571     			}
572     		}
573     		err = sem_revalidate(semid, sma, nsems, S_IWUGO);
574     		if(err)
575     			goto out_free;
576     
577     		for (i = 0; i < nsems; i++)
578     			sma->sem_base[i].semval = sem_io[i];
579     		for (un = sma->undo; un; un = un->id_next)
580     			for (i = 0; i < nsems; i++)
581     				un->semadj[i] = 0;
582     		sma->sem_ctime = CURRENT_TIME;
583     		/* maybe some queued-up processes were waiting for this */
584     		update_queue(sma);
585     		err = 0;
586     		goto out_unlock;
587     	}
588     	case IPC_STAT:
589     	{
590     		struct semid64_ds tbuf;
591     		memset(&tbuf,0,sizeof(tbuf));
592     		kernel_to_ipc64_perm(&sma->sem_perm, &tbuf.sem_perm);
593     		tbuf.sem_otime  = sma->sem_otime;
594     		tbuf.sem_ctime  = sma->sem_ctime;
595     		tbuf.sem_nsems  = sma->sem_nsems;
596     		sem_unlock(semid);
597     		if (copy_semid_to_user (arg.buf, &tbuf, version))
598     			return -EFAULT;
599     		return 0;
600     	}
601     	/* GETVAL, GETPID, GETNCTN, GETZCNT, SETVAL: fall-through */
602     	}
603     	err = -EINVAL;
604     	if(semnum < 0 || semnum >= nsems)
605     		goto out_unlock;
606     
607     	curr = &sma->sem_base[semnum];
608     
609     	switch (cmd) {
610     	case GETVAL:
611     		err = curr->semval;
612     		goto out_unlock;
613     	case GETPID:
614     		err = curr->sempid & 0xffff;
615     		goto out_unlock;
616     	case GETNCNT:
617     		err = count_semncnt(sma,semnum);
618     		goto out_unlock;
619     	case GETZCNT:
620     		err = count_semzcnt(sma,semnum);
621     		goto out_unlock;
622     	case SETVAL:
623     	{
624     		int val = arg.val;
625     		struct sem_undo *un;
626     		err = -ERANGE;
627     		if (val > SEMVMX || val < 0)
628     			goto out_unlock;
629     
630     		for (un = sma->undo; un; un = un->id_next)
631     			un->semadj[semnum] = 0;
632     		curr->semval = val;
633     		sma->sem_ctime = CURRENT_TIME;
634     		/* maybe some queued-up processes were waiting for this */
635     		update_queue(sma);
636     		err = 0;
637     		goto out_unlock;
638     	}
639     	}
640     out_unlock:
641     	sem_unlock(semid);
642     out_free:
643     	if(sem_io != fast_sem_io)
644     		ipc_free(sem_io, sizeof(ushort)*nsems);
645     	return err;
646     }
647     
648     struct sem_setbuf {
649     	uid_t	uid;
650     	gid_t	gid;
651     	mode_t	mode;
652     };
653     
654     static inline unsigned long copy_semid_from_user(struct sem_setbuf *out, void *buf, int version)
655     {
656     	switch(version) {
657     	case IPC_64:
658     	    {
659     		struct semid64_ds tbuf;
660     
661     		if(copy_from_user(&tbuf, buf, sizeof(tbuf)))
662     			return -EFAULT;
663     
664     		out->uid	= tbuf.sem_perm.uid;
665     		out->gid	= tbuf.sem_perm.gid;
666     		out->mode	= tbuf.sem_perm.mode;
667     
668     		return 0;
669     	    }
670     	case IPC_OLD:
671     	    {
672     		struct semid_ds tbuf_old;
673     
674     		if(copy_from_user(&tbuf_old, buf, sizeof(tbuf_old)))
675     			return -EFAULT;
676     
677     		out->uid	= tbuf_old.sem_perm.uid;
678     		out->gid	= tbuf_old.sem_perm.gid;
679     		out->mode	= tbuf_old.sem_perm.mode;
680     
681     		return 0;
682     	    }
683     	default:
684     		return -EINVAL;
685     	}
686     }
687     
688     int semctl_down(int semid, int semnum, int cmd, int version, union semun arg)
689     {
690     	struct sem_array *sma;
691     	int err;
692     	struct sem_setbuf setbuf;
693     	struct kern_ipc_perm *ipcp;
694     
695     	if(cmd == IPC_SET) {
696     		if(copy_semid_from_user (&setbuf, arg.buf, version))
697     			return -EFAULT;
698     	}
699     	sma = sem_lock(semid);
700     	if(sma==NULL)
701     		return -EINVAL;
702     
703     	if (sem_checkid(sma,semid)) {
704     		err=-EIDRM;
705     		goto out_unlock;
706     	}	
707     	ipcp = &sma->sem_perm;
708     	
709     	if (current->euid != ipcp->cuid && 
710     	    current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN)) {
711     	    	err=-EPERM;
712     		goto out_unlock;
713     	}
714     
715     	switch(cmd){
716     	case IPC_RMID:
717     		freeary(semid);
718     		err = 0;
719     		break;
720     	case IPC_SET:
721     		ipcp->uid = setbuf.uid;
722     		ipcp->gid = setbuf.gid;
723     		ipcp->mode = (ipcp->mode & ~S_IRWXUGO)
724     				| (setbuf.mode & S_IRWXUGO);
725     		sma->sem_ctime = CURRENT_TIME;
726     		sem_unlock(semid);
727     		err = 0;
728     		break;
729     	default:
730     		sem_unlock(semid);
731     		err = -EINVAL;
732     		break;
733     	}
734     	return err;
735     
736     out_unlock:
737     	sem_unlock(semid);
738     	return err;
739     }
740     
741     asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg)
742     {
743     	int err = -EINVAL;
744     	int version;
745     
746     	if (semid < 0)
747     		return -EINVAL;
748     
749     	version = ipc_parse_version(&cmd);
750     
751     	switch(cmd) {
752     	case IPC_INFO:
753     	case SEM_INFO:
754     	case SEM_STAT:
755     		err = semctl_nolock(semid,semnum,cmd,version,arg);
756     		return err;
757     	case GETALL:
758     	case GETVAL:
759     	case GETPID:
760     	case GETNCNT:
761     	case GETZCNT:
762     	case IPC_STAT:
763     	case SETVAL:
764     	case SETALL:
765     		err = semctl_main(semid,semnum,cmd,version,arg);
766     		return err;
767     	case IPC_RMID:
768     	case IPC_SET:
769     		down(&sem_ids.sem);
770     		err = semctl_down(semid,semnum,cmd,version,arg);
771     		up(&sem_ids.sem);
772     		return err;
773     	default:
774     		return -EINVAL;
775     	}
776     }
777     
778     static struct sem_undo* freeundos(struct sem_array *sma, struct sem_undo* un)
779     {
780     	struct sem_undo* u;
781     	struct sem_undo** up;
782     
783     	for(up = &current->semundo;(u=*up);up=&u->proc_next) {
784     		if(un==u) {
785     			un=u->proc_next;
786     			*up=un;
787     			kfree(u);
788     			return un;
789     		}
790     	}
791     	printk ("freeundos undo list error id=%d\n", un->semid);
792     	return un->proc_next;
793     }
794     
795     /* returns without sem_lock on error! */
796     static int alloc_undo(struct sem_array *sma, struct sem_undo** unp, int semid, int alter)
797     {
798     	int size, nsems, error;
799     	struct sem_undo *un;
800     
801     	nsems = sma->sem_nsems;
802     	size = sizeof(struct sem_undo) + sizeof(short)*nsems;
803     	sem_unlock(semid);
804     
805     	un = (struct sem_undo *) kmalloc(size, GFP_KERNEL);
806     	if (!un)
807     		return -ENOMEM;
808     
809     	memset(un, 0, size);
810     	error = sem_revalidate(semid, sma, nsems, alter ? S_IWUGO : S_IRUGO);
811     	if(error) {
812     		kfree(un);
813     		return error;
814     	}
815     
816     	un->semadj = (short *) &un[1];
817     	un->semid = semid;
818     	un->proc_next = current->semundo;
819     	current->semundo = un;
820     	un->id_next = sma->undo;
821     	sma->undo = un;
822     	*unp = un;
823     	return 0;
824     }
825     
826     asmlinkage long sys_semop (int semid, struct sembuf *tsops, unsigned nsops)
827     {
828     	int error = -EINVAL;
829     	struct sem_array *sma;
830     	struct sembuf fast_sops[SEMOPM_FAST];
831     	struct sembuf* sops = fast_sops, *sop;
832     	struct sem_undo *un;
833     	int undos = 0, decrease = 0, alter = 0;
834     	struct sem_queue queue;
835     
836     	if (nsops < 1 || semid < 0)
837     		return -EINVAL;
838     	if (nsops > sc_semopm)
839     		return -E2BIG;
840     	if(nsops > SEMOPM_FAST) {
841     		sops = kmalloc(sizeof(*sops)*nsops,GFP_KERNEL);
842     		if(sops==NULL)
843     			return -ENOMEM;
844     	}
845     	if (copy_from_user (sops, tsops, nsops * sizeof(*tsops))) {
846     		error=-EFAULT;
847     		goto out_free;
848     	}
849     	sma = sem_lock(semid);
850     	error=-EINVAL;
851     	if(sma==NULL)
852     		goto out_free;
853     	error = -EIDRM;
854     	if (sem_checkid(sma,semid))
855     		goto out_unlock_free;
856     	error = -EFBIG;
857     	for (sop = sops; sop < sops + nsops; sop++) {
858     		if (sop->sem_num >= sma->sem_nsems)
859     			goto out_unlock_free;
860     		if (sop->sem_flg & SEM_UNDO)
861     			undos++;
862     		if (sop->sem_op < 0)
863     			decrease = 1;
864     		if (sop->sem_op > 0)
865     			alter = 1;
866     	}
867     	alter |= decrease;
868     
869     	error = -EACCES;
870     	if (ipcperms(&sma->sem_perm, alter ? S_IWUGO : S_IRUGO))
871     		goto out_unlock_free;
872     	if (undos) {
873     		/* Make sure we have an undo structure
874     		 * for this process and this semaphore set.
875     		 */
876     		un=current->semundo;
877     		while(un != NULL) {
878     			if(un->semid==semid)
879     				break;
880     			if(un->semid==-1)
881     				un=freeundos(sma,un);
882     			 else
883     				un=un->proc_next;
884     		}
885     		if (!un) {
886     			error = alloc_undo(sma,&un,semid,alter);
887     			if(error)
888     				goto out_free;
889     		}
890     	} else
891     		un = NULL;
892     
893     	error = try_atomic_semop (sma, sops, nsops, un, current->pid, 0);
894     	if (error <= 0)
895     		goto update;
896     
897     	/* We need to sleep on this operation, so we put the current
898     	 * task into the pending queue and go to sleep.
899     	 */
900     		
901     	queue.sma = sma;
902     	queue.sops = sops;
903     	queue.nsops = nsops;
904     	queue.undo = un;
905     	queue.pid = current->pid;
906     	queue.alter = decrease;
907     	queue.id = semid;
908     	if (alter)
909     		append_to_queue(sma ,&queue);
910     	else
911     		prepend_to_queue(sma ,&queue);
912     	current->semsleeping = &queue;
913     
914     	for (;;) {
915     		struct sem_array* tmp;
916     		queue.status = -EINTR;
917     		queue.sleeper = current;
918     		current->state = TASK_INTERRUPTIBLE;
919     		sem_unlock(semid);
920     
921     		schedule();
922     
923     		tmp = sem_lock(semid);
924     		if(tmp==NULL) {
925     			if(queue.prev != NULL)
926     				BUG();
927     			current->semsleeping = NULL;
928     			error = -EIDRM;
929     			goto out_free;
930     		}
931     		/*
932     		 * If queue.status == 1 we where woken up and
933     		 * have to retry else we simply return.
934     		 * If an interrupt occurred we have to clean up the
935     		 * queue
936     		 *
937     		 */
938     		if (queue.status == 1)
939     		{
940     			error = try_atomic_semop (sma, sops, nsops, un,
941     						  current->pid,0);
942     			if (error <= 0) 
943     				break;
944     		} else {
945     			error = queue.status;
946     			if (queue.prev) /* got Interrupt */
947     				break;
948     			/* Everything done by update_queue */
949     			current->semsleeping = NULL;
950     			goto out_unlock_free;
951     		}
952     	}
953     	current->semsleeping = NULL;
954     	remove_from_queue(sma,&queue);
955     update:
956     	if (alter)
957     		update_queue (sma);
958     out_unlock_free:
959     	sem_unlock(semid);
960     out_free:
961     	if(sops != fast_sops)
962     		kfree(sops);
963     	return error;
964     }
965     
966     /*
967      * add semadj values to semaphores, free undo structures.
968      * undo structures are not freed when semaphore arrays are destroyed
969      * so some of them may be out of date.
970      * IMPLEMENTATION NOTE: There is some confusion over whether the
971      * set of adjustments that needs to be done should be done in an atomic
972      * manner or not. That is, if we are attempting to decrement the semval
973      * should we queue up and wait until we can do so legally?
974      * The original implementation attempted to do this (queue and wait).
975      * The current implementation does not do so. The POSIX standard
976      * and SVID should be consulted to determine what behavior is mandated.
977      */
978     void sem_exit (void)
979     {
980     	struct sem_queue *q;
981     	struct sem_undo *u, *un = NULL, **up, **unp;
982     	struct sem_array *sma;
983     	int nsems, i;
984     
985     	/* If the current process was sleeping for a semaphore,
986     	 * remove it from the queue.
987     	 */
988     	if ((q = current->semsleeping)) {
989     		int semid = q->id;
990     		sma = sem_lock(semid);
991     		current->semsleeping = NULL;
992     
993     		if (q->prev) {
994     			if(sma==NULL)
995     				BUG();
996     			remove_from_queue(q->sma,q);
997     		}
998     		if(sma!=NULL)
999     			sem_unlock(semid);
1000     	}
1001     
1002     	for (up = &current->semundo; (u = *up); *up = u->proc_next, kfree(u)) {
1003     		int semid = u->semid;
1004     		if(semid == -1)
1005     			continue;
1006     		sma = sem_lock(semid);
1007     		if (sma == NULL)
1008     			continue;
1009     
1010     		if (u->semid == -1)
1011     			goto next_entry;
1012     
1013     		if (sem_checkid(sma,u->semid))
1014     			goto next_entry;
1015     
1016     		/* remove u from the sma->undo list */
1017     		for (unp = &sma->undo; (un = *unp); unp = &un->id_next) {
1018     			if (u == un)
1019     				goto found;
1020     		}
1021     		printk ("sem_exit undo list error id=%d\n", u->semid);
1022     		goto next_entry;
1023     found:
1024     		*unp = un->id_next;
1025     		/* perform adjustments registered in u */
1026     		nsems = sma->sem_nsems;
1027     		for (i = 0; i < nsems; i++) {
1028     			struct sem * sem = &sma->sem_base[i];
1029     			sem->semval += u->semadj[i];
1030     			if (sem->semval < 0)
1031     				sem->semval = 0; /* shouldn't happen */
1032     			sem->sempid = current->pid;
1033     		}
1034     		sma->sem_otime = CURRENT_TIME;
1035     		/* maybe some queued-up processes were waiting for this */
1036     		update_queue(sma);
1037     next_entry:
1038     		sem_unlock(semid);
1039     	}
1040     	current->semundo = NULL;
1041     }
1042     
1043     #ifdef CONFIG_PROC_FS
1044     static int sysvipc_sem_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
1045     {
1046     	off_t pos = 0;
1047     	off_t begin = 0;
1048     	int i, len = 0;
1049     
1050     	len += sprintf(buffer, "       key      semid perms      nsems   uid   gid  cuid  cgid      otime      ctime\n");
1051     	down(&sem_ids.sem);
1052     
1053     	for(i = 0; i <= sem_ids.max_id; i++) {
1054     		struct sem_array *sma;
1055     		sma = sem_lock(i);
1056     		if(sma) {
1057     			len += sprintf(buffer + len, "%10d %10d  %4o %10lu %5u %5u %5u %5u %10lu %10lu\n",
1058     				sma->sem_perm.key,
1059     				sem_buildid(i,sma->sem_perm.seq),
1060     				sma->sem_perm.mode,
1061     				sma->sem_nsems,
1062     				sma->sem_perm.uid,
1063     				sma->sem_perm.gid,
1064     				sma->sem_perm.cuid,
1065     				sma->sem_perm.cgid,
1066     				sma->sem_otime,
1067     				sma->sem_ctime);
1068     			sem_unlock(i);
1069     
1070     			pos += len;
1071     			if(pos < offset) {
1072     				len = 0;
1073     	    			begin = pos;
1074     			}
1075     			if(pos > offset + length)
1076     				goto done;
1077     		}
1078     	}
1079     	*eof = 1;
1080     done:
1081     	up(&sem_ids.sem);
1082     	*start = buffer + (offset - begin);
1083     	len -= (offset - begin);
1084     	if(len > length)
1085     		len = length;
1086     	if(len < 0)
1087     		len = 0;
1088     	return len;
1089     }
1090     #endif
1091