]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - ipc/compat.c
seqlock: Don't smp_rmb in seqlock reader spin loop
[karo-tx-linux.git] / ipc / compat.c
1 /*
2  * 32 bit compatibility code for System V IPC
3  *
4  * Copyright (C) 1997,1998      Jakub Jelinek (jj@sunsite.mff.cuni.cz)
5  * Copyright (C) 1997           David S. Miller (davem@caip.rutgers.edu)
6  * Copyright (C) 1999           Arun Sharma <arun.sharma@intel.com>
7  * Copyright (C) 2000           VA Linux Co
8  * Copyright (C) 2000           Don Dugger <n0ano@valinux.com>
9  * Copyright (C) 2000           Hewlett-Packard Co.
10  * Copyright (C) 2000           David Mosberger-Tang <davidm@hpl.hp.com>
11  * Copyright (C) 2000           Gerhard Tonn (ton@de.ibm.com)
12  * Copyright (C) 2000-2002      Andi Kleen, SuSE Labs (x86-64 port)
13  * Copyright (C) 2000           Silicon Graphics, Inc.
14  * Copyright (C) 2001           IBM
15  * Copyright (C) 2004           IBM Deutschland Entwicklung GmbH, IBM Corporation
16  * Copyright (C) 2004           Arnd Bergmann (arnd@arndb.de)
17  *
18  * This code is collected from the versions for sparc64, mips64, s390x, ia64,
19  * ppc64 and x86_64, all of which are based on the original sparc64 version
20  * by Jakub Jelinek.
21  *
22  */
23 #include <linux/compat.h>
24 #include <linux/errno.h>
25 #include <linux/highuid.h>
26 #include <linux/init.h>
27 #include <linux/msg.h>
28 #include <linux/shm.h>
29 #include <linux/slab.h>
30 #include <linux/syscalls.h>
31
32 #include <linux/mutex.h>
33 #include <asm/uaccess.h>
34
35 #include "util.h"
36
37 struct compat_msgbuf {
38         compat_long_t mtype;
39         char mtext[1];
40 };
41
42 struct compat_ipc_perm {
43         key_t key;
44         __compat_uid_t uid;
45         __compat_gid_t gid;
46         __compat_uid_t cuid;
47         __compat_gid_t cgid;
48         compat_mode_t mode;
49         unsigned short seq;
50 };
51
52 struct compat_semid_ds {
53         struct compat_ipc_perm sem_perm;
54         compat_time_t sem_otime;
55         compat_time_t sem_ctime;
56         compat_uptr_t sem_base;
57         compat_uptr_t sem_pending;
58         compat_uptr_t sem_pending_last;
59         compat_uptr_t undo;
60         unsigned short sem_nsems;
61 };
62
63 struct compat_msqid_ds {
64         struct compat_ipc_perm msg_perm;
65         compat_uptr_t msg_first;
66         compat_uptr_t msg_last;
67         compat_time_t msg_stime;
68         compat_time_t msg_rtime;
69         compat_time_t msg_ctime;
70         compat_ulong_t msg_lcbytes;
71         compat_ulong_t msg_lqbytes;
72         unsigned short msg_cbytes;
73         unsigned short msg_qnum;
74         unsigned short msg_qbytes;
75         compat_ipc_pid_t msg_lspid;
76         compat_ipc_pid_t msg_lrpid;
77 };
78
79 struct compat_shmid_ds {
80         struct compat_ipc_perm shm_perm;
81         int shm_segsz;
82         compat_time_t shm_atime;
83         compat_time_t shm_dtime;
84         compat_time_t shm_ctime;
85         compat_ipc_pid_t shm_cpid;
86         compat_ipc_pid_t shm_lpid;
87         unsigned short shm_nattch;
88         unsigned short shm_unused;
89         compat_uptr_t shm_unused2;
90         compat_uptr_t shm_unused3;
91 };
92
93 struct compat_ipc_kludge {
94         compat_uptr_t msgp;
95         compat_long_t msgtyp;
96 };
97
98 struct compat_shminfo64 {
99         compat_ulong_t shmmax;
100         compat_ulong_t shmmin;
101         compat_ulong_t shmmni;
102         compat_ulong_t shmseg;
103         compat_ulong_t shmall;
104         compat_ulong_t __unused1;
105         compat_ulong_t __unused2;
106         compat_ulong_t __unused3;
107         compat_ulong_t __unused4;
108 };
109
110 struct compat_shm_info {
111         compat_int_t used_ids;
112         compat_ulong_t shm_tot, shm_rss, shm_swp;
113         compat_ulong_t swap_attempts, swap_successes;
114 };
115
116 extern int sem_ctls[];
117 #define sc_semopm       (sem_ctls[2])
118
119 static inline int compat_ipc_parse_version(int *cmd)
120 {
121         int version = *cmd & IPC_64;
122
123         /* this is tricky: architectures that have support for the old
124          * ipc structures in 64 bit binaries need to have IPC_64 set
125          * in cmd, the others need to have it cleared */
126 #ifndef ipc_parse_version
127         *cmd |= IPC_64;
128 #else
129         *cmd &= ~IPC_64;
130 #endif
131         return version;
132 }
133
134 static inline int __get_compat_ipc64_perm(struct ipc64_perm *p64,
135                                           struct compat_ipc64_perm __user *up64)
136 {
137         int err;
138
139         err  = __get_user(p64->uid, &up64->uid);
140         err |= __get_user(p64->gid, &up64->gid);
141         err |= __get_user(p64->mode, &up64->mode);
142         return err;
143 }
144
145 static inline int __get_compat_ipc_perm(struct ipc64_perm *p,
146                                         struct compat_ipc_perm __user *up)
147 {
148         int err;
149
150         err  = __get_user(p->uid, &up->uid);
151         err |= __get_user(p->gid, &up->gid);
152         err |= __get_user(p->mode, &up->mode);
153         return err;
154 }
155
156 static inline int __put_compat_ipc64_perm(struct ipc64_perm *p64,
157                                           struct compat_ipc64_perm __user *up64)
158 {
159         int err;
160
161         err  = __put_user(p64->key, &up64->key);
162         err |= __put_user(p64->uid, &up64->uid);
163         err |= __put_user(p64->gid, &up64->gid);
164         err |= __put_user(p64->cuid, &up64->cuid);
165         err |= __put_user(p64->cgid, &up64->cgid);
166         err |= __put_user(p64->mode, &up64->mode);
167         err |= __put_user(p64->seq, &up64->seq);
168         return err;
169 }
170
171 static inline int __put_compat_ipc_perm(struct ipc64_perm *p,
172                                         struct compat_ipc_perm __user *up)
173 {
174         int err;
175         __compat_uid_t u;
176         __compat_gid_t g;
177
178         err  = __put_user(p->key, &up->key);
179         SET_UID(u, p->uid);
180         err |= __put_user(u, &up->uid);
181         SET_GID(g, p->gid);
182         err |= __put_user(g, &up->gid);
183         SET_UID(u, p->cuid);
184         err |= __put_user(u, &up->cuid);
185         SET_GID(g, p->cgid);
186         err |= __put_user(g, &up->cgid);
187         err |= __put_user(p->mode, &up->mode);
188         err |= __put_user(p->seq, &up->seq);
189         return err;
190 }
191
192 static inline int get_compat_semid64_ds(struct semid64_ds *s64,
193                                         struct compat_semid64_ds __user *up64)
194 {
195         if (!access_ok (VERIFY_READ, up64, sizeof(*up64)))
196                 return -EFAULT;
197         return __get_compat_ipc64_perm(&s64->sem_perm, &up64->sem_perm);
198 }
199
200 static inline int get_compat_semid_ds(struct semid64_ds *s,
201                                       struct compat_semid_ds __user *up)
202 {
203         if (!access_ok (VERIFY_READ, up, sizeof(*up)))
204                 return -EFAULT;
205         return __get_compat_ipc_perm(&s->sem_perm, &up->sem_perm);
206 }
207
208 static inline int put_compat_semid64_ds(struct semid64_ds *s64,
209                                         struct compat_semid64_ds __user *up64)
210 {
211         int err;
212
213         if (!access_ok (VERIFY_WRITE, up64, sizeof(*up64)))
214                 return -EFAULT;
215         err  = __put_compat_ipc64_perm(&s64->sem_perm, &up64->sem_perm);
216         err |= __put_user(s64->sem_otime, &up64->sem_otime);
217         err |= __put_user(s64->sem_ctime, &up64->sem_ctime);
218         err |= __put_user(s64->sem_nsems, &up64->sem_nsems);
219         return err;
220 }
221
222 static inline int put_compat_semid_ds(struct semid64_ds *s,
223                                       struct compat_semid_ds __user *up)
224 {
225         int err;
226
227         if (!access_ok (VERIFY_WRITE, up, sizeof(*up)))
228                 return -EFAULT;
229         err  = __put_compat_ipc_perm(&s->sem_perm, &up->sem_perm);
230         err |= __put_user(s->sem_otime, &up->sem_otime);
231         err |= __put_user(s->sem_ctime, &up->sem_ctime);
232         err |= __put_user(s->sem_nsems, &up->sem_nsems);
233         return err;
234 }
235
236 long compat_sys_semctl(int first, int second, int third, void __user *uptr)
237 {
238         union semun fourth;
239         u32 pad;
240         int err, err2;
241         struct semid64_ds s64;
242         struct semid64_ds __user *up64;
243         int version = compat_ipc_parse_version(&third);
244
245         memset(&s64, 0, sizeof(s64));
246
247         if (!uptr)
248                 return -EINVAL;
249         if (get_user(pad, (u32 __user *) uptr))
250                 return -EFAULT;
251         if ((third & (~IPC_64)) == SETVAL)
252                 fourth.val = (int) pad;
253         else
254                 fourth.__pad = compat_ptr(pad);
255         switch (third & (~IPC_64)) {
256         case IPC_INFO:
257         case IPC_RMID:
258         case SEM_INFO:
259         case GETVAL:
260         case GETPID:
261         case GETNCNT:
262         case GETZCNT:
263         case GETALL:
264         case SETVAL:
265         case SETALL:
266                 err = sys_semctl(first, second, third, fourth);
267                 break;
268
269         case IPC_STAT:
270         case SEM_STAT:
271                 up64 = compat_alloc_user_space(sizeof(s64));
272                 fourth.__pad = up64;
273                 err = sys_semctl(first, second, third, fourth);
274                 if (err < 0)
275                         break;
276                 if (copy_from_user(&s64, up64, sizeof(s64)))
277                         err2 = -EFAULT;
278                 else if (version == IPC_64)
279                         err2 = put_compat_semid64_ds(&s64, compat_ptr(pad));
280                 else
281                         err2 = put_compat_semid_ds(&s64, compat_ptr(pad));
282                 if (err2)
283                         err = -EFAULT;
284                 break;
285
286         case IPC_SET:
287                 if (version == IPC_64) {
288                         err = get_compat_semid64_ds(&s64, compat_ptr(pad));
289                 } else {
290                         err = get_compat_semid_ds(&s64, compat_ptr(pad));
291                 }
292                 up64 = compat_alloc_user_space(sizeof(s64));
293                 if (copy_to_user(up64, &s64, sizeof(s64)))
294                         err = -EFAULT;
295                 if (err)
296                         break;
297
298                 fourth.__pad = up64;
299                 err = sys_semctl(first, second, third, fourth);
300                 break;
301
302         default:
303                 err = -EINVAL;
304                 break;
305         }
306         return err;
307 }
308
309 long compat_sys_msgsnd(int first, int second, int third, void __user *uptr)
310 {
311         struct compat_msgbuf __user *up = uptr;
312         long type;
313
314         if (first < 0)
315                 return -EINVAL;
316         if (second < 0)
317                 return -EINVAL;
318
319         if (get_user(type, &up->mtype))
320                 return -EFAULT;
321
322         return do_msgsnd(first, type, up->mtext, second, third);
323 }
324
325 long compat_sys_msgrcv(int first, int second, int msgtyp, int third,
326                            int version, void __user *uptr)
327 {
328         struct compat_msgbuf __user *up;
329         long type;
330         int err;
331
332         if (first < 0)
333                 return -EINVAL;
334         if (second < 0)
335                 return -EINVAL;
336
337         if (!version) {
338                 struct compat_ipc_kludge ipck;
339                 err = -EINVAL;
340                 if (!uptr)
341                         goto out;
342                 err = -EFAULT;
343                 if (copy_from_user (&ipck, uptr, sizeof(ipck)))
344                         goto out;
345                 uptr = compat_ptr(ipck.msgp);
346                 msgtyp = ipck.msgtyp;
347         }
348         up = uptr;
349         err = do_msgrcv(first, &type, up->mtext, second, msgtyp, third);
350         if (err < 0)
351                 goto out;
352         if (put_user(type, &up->mtype))
353                 err = -EFAULT;
354 out:
355         return err;
356 }
357
358 static inline int get_compat_msqid64(struct msqid64_ds *m64,
359                                      struct compat_msqid64_ds __user *up64)
360 {
361         int err;
362
363         if (!access_ok(VERIFY_READ, up64, sizeof(*up64)))
364                 return -EFAULT;
365         err  = __get_compat_ipc64_perm(&m64->msg_perm, &up64->msg_perm);
366         err |= __get_user(m64->msg_qbytes, &up64->msg_qbytes);
367         return err;
368 }
369
370 static inline int get_compat_msqid(struct msqid64_ds *m,
371                                    struct compat_msqid_ds __user *up)
372 {
373         int err;
374
375         if (!access_ok(VERIFY_READ, up, sizeof(*up)))
376                 return -EFAULT;
377         err  = __get_compat_ipc_perm(&m->msg_perm, &up->msg_perm);
378         err |= __get_user(m->msg_qbytes, &up->msg_qbytes);
379         return err;
380 }
381
382 static inline int put_compat_msqid64_ds(struct msqid64_ds *m64,
383                                  struct compat_msqid64_ds __user *up64)
384 {
385         int err;
386
387         if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
388                 return -EFAULT;
389         err  = __put_compat_ipc64_perm(&m64->msg_perm, &up64->msg_perm);
390         err |= __put_user(m64->msg_stime, &up64->msg_stime);
391         err |= __put_user(m64->msg_rtime, &up64->msg_rtime);
392         err |= __put_user(m64->msg_ctime, &up64->msg_ctime);
393         err |= __put_user(m64->msg_cbytes, &up64->msg_cbytes);
394         err |= __put_user(m64->msg_qnum, &up64->msg_qnum);
395         err |= __put_user(m64->msg_qbytes, &up64->msg_qbytes);
396         err |= __put_user(m64->msg_lspid, &up64->msg_lspid);
397         err |= __put_user(m64->msg_lrpid, &up64->msg_lrpid);
398         return err;
399 }
400
401 static inline int put_compat_msqid_ds(struct msqid64_ds *m,
402                                       struct compat_msqid_ds __user *up)
403 {
404         int err;
405
406         if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
407                 return -EFAULT;
408         err  = __put_compat_ipc_perm(&m->msg_perm, &up->msg_perm);
409         err |= __put_user(m->msg_stime, &up->msg_stime);
410         err |= __put_user(m->msg_rtime, &up->msg_rtime);
411         err |= __put_user(m->msg_ctime, &up->msg_ctime);
412         err |= __put_user(m->msg_cbytes, &up->msg_cbytes);
413         err |= __put_user(m->msg_qnum, &up->msg_qnum);
414         err |= __put_user(m->msg_qbytes, &up->msg_qbytes);
415         err |= __put_user(m->msg_lspid, &up->msg_lspid);
416         err |= __put_user(m->msg_lrpid, &up->msg_lrpid);
417         return err;
418 }
419
420 long compat_sys_msgctl(int first, int second, void __user *uptr)
421 {
422         int err, err2;
423         struct msqid64_ds m64;
424         int version = compat_ipc_parse_version(&second);
425         void __user *p;
426
427         memset(&m64, 0, sizeof(m64));
428
429         switch (second & (~IPC_64)) {
430         case IPC_INFO:
431         case IPC_RMID:
432         case MSG_INFO:
433                 err = sys_msgctl(first, second, uptr);
434                 break;
435
436         case IPC_SET:
437                 if (version == IPC_64) {
438                         err = get_compat_msqid64(&m64, uptr);
439                 } else {
440                         err = get_compat_msqid(&m64, uptr);
441                 }
442                 if (err)
443                         break;
444                 p = compat_alloc_user_space(sizeof(m64));
445                 if (copy_to_user(p, &m64, sizeof(m64)))
446                         err = -EFAULT;
447                 else
448                         err = sys_msgctl(first, second, p);
449                 break;
450
451         case IPC_STAT:
452         case MSG_STAT:
453                 p = compat_alloc_user_space(sizeof(m64));
454                 err = sys_msgctl(first, second, p);
455                 if (err < 0)
456                         break;
457                 if (copy_from_user(&m64, p, sizeof(m64)))
458                         err2 = -EFAULT;
459                 else if (version == IPC_64)
460                         err2 = put_compat_msqid64_ds(&m64, uptr);
461                 else
462                         err2 = put_compat_msqid_ds(&m64, uptr);
463                 if (err2)
464                         err = -EFAULT;
465                 break;
466
467         default:
468                 err = -EINVAL;
469                 break;
470         }
471         return err;
472 }
473
474 long compat_sys_shmat(int first, int second, compat_uptr_t third, int version,
475                         void __user *uptr)
476 {
477         int err;
478         unsigned long raddr;
479         compat_ulong_t __user *uaddr;
480
481         if (version == 1)
482                 return -EINVAL;
483         err = do_shmat(first, uptr, second, &raddr);
484         if (err < 0)
485                 return err;
486         uaddr = compat_ptr(third);
487         return put_user(raddr, uaddr);
488 }
489
490 static inline int get_compat_shmid64_ds(struct shmid64_ds *s64,
491                                         struct compat_shmid64_ds __user *up64)
492 {
493         if (!access_ok(VERIFY_READ, up64, sizeof(*up64)))
494                 return -EFAULT;
495         return __get_compat_ipc64_perm(&s64->shm_perm, &up64->shm_perm);
496 }
497
498 static inline int get_compat_shmid_ds(struct shmid64_ds *s,
499                                       struct compat_shmid_ds __user *up)
500 {
501         if (!access_ok(VERIFY_READ, up, sizeof(*up)))
502                 return -EFAULT;
503         return __get_compat_ipc_perm(&s->shm_perm, &up->shm_perm);
504 }
505
506 static inline int put_compat_shmid64_ds(struct shmid64_ds *s64,
507                                         struct compat_shmid64_ds __user *up64)
508 {
509         int err;
510
511         if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
512                 return -EFAULT;
513         err  = __put_compat_ipc64_perm(&s64->shm_perm, &up64->shm_perm);
514         err |= __put_user(s64->shm_atime, &up64->shm_atime);
515         err |= __put_user(s64->shm_dtime, &up64->shm_dtime);
516         err |= __put_user(s64->shm_ctime, &up64->shm_ctime);
517         err |= __put_user(s64->shm_segsz, &up64->shm_segsz);
518         err |= __put_user(s64->shm_nattch, &up64->shm_nattch);
519         err |= __put_user(s64->shm_cpid, &up64->shm_cpid);
520         err |= __put_user(s64->shm_lpid, &up64->shm_lpid);
521         return err;
522 }
523
524 static inline int put_compat_shmid_ds(struct shmid64_ds *s,
525                                       struct compat_shmid_ds __user *up)
526 {
527         int err;
528
529         if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
530                 return -EFAULT;
531         err  = __put_compat_ipc_perm(&s->shm_perm, &up->shm_perm);
532         err |= __put_user(s->shm_atime, &up->shm_atime);
533         err |= __put_user(s->shm_dtime, &up->shm_dtime);
534         err |= __put_user(s->shm_ctime, &up->shm_ctime);
535         err |= __put_user(s->shm_segsz, &up->shm_segsz);
536         err |= __put_user(s->shm_nattch, &up->shm_nattch);
537         err |= __put_user(s->shm_cpid, &up->shm_cpid);
538         err |= __put_user(s->shm_lpid, &up->shm_lpid);
539         return err;
540 }
541
542 static inline int put_compat_shminfo64(struct shminfo64 *smi,
543                                        struct compat_shminfo64 __user *up64)
544 {
545         int err;
546
547         if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
548                 return -EFAULT;
549         if (smi->shmmax > INT_MAX)
550                 smi->shmmax = INT_MAX;
551         err  = __put_user(smi->shmmax, &up64->shmmax);
552         err |= __put_user(smi->shmmin, &up64->shmmin);
553         err |= __put_user(smi->shmmni, &up64->shmmni);
554         err |= __put_user(smi->shmseg, &up64->shmseg);
555         err |= __put_user(smi->shmall, &up64->shmall);
556         return err;
557 }
558
559 static inline int put_compat_shminfo(struct shminfo64 *smi,
560                                      struct shminfo __user *up)
561 {
562         int err;
563
564         if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
565                 return -EFAULT;
566         if (smi->shmmax > INT_MAX)
567                 smi->shmmax = INT_MAX;
568         err  = __put_user(smi->shmmax, &up->shmmax);
569         err |= __put_user(smi->shmmin, &up->shmmin);
570         err |= __put_user(smi->shmmni, &up->shmmni);
571         err |= __put_user(smi->shmseg, &up->shmseg);
572         err |= __put_user(smi->shmall, &up->shmall);
573         return err;
574 }
575
576 static inline int put_compat_shm_info(struct shm_info __user *ip,
577                                       struct compat_shm_info __user *uip)
578 {
579         int err;
580         struct shm_info si;
581
582         if (!access_ok(VERIFY_WRITE, uip, sizeof(*uip)) ||
583             copy_from_user(&si, ip, sizeof(si)))
584                 return -EFAULT;
585         err  = __put_user(si.used_ids, &uip->used_ids);
586         err |= __put_user(si.shm_tot, &uip->shm_tot);
587         err |= __put_user(si.shm_rss, &uip->shm_rss);
588         err |= __put_user(si.shm_swp, &uip->shm_swp);
589         err |= __put_user(si.swap_attempts, &uip->swap_attempts);
590         err |= __put_user(si.swap_successes, &uip->swap_successes);
591         return err;
592 }
593
594 long compat_sys_shmctl(int first, int second, void __user *uptr)
595 {
596         void __user *p;
597         struct shmid64_ds s64;
598         struct shminfo64 smi;
599         int err, err2;
600         int version = compat_ipc_parse_version(&second);
601
602         memset(&s64, 0, sizeof(s64));
603
604         switch (second & (~IPC_64)) {
605         case IPC_RMID:
606         case SHM_LOCK:
607         case SHM_UNLOCK:
608                 err = sys_shmctl(first, second, uptr);
609                 break;
610
611         case IPC_INFO:
612                 p = compat_alloc_user_space(sizeof(smi));
613                 err = sys_shmctl(first, second, p);
614                 if (err < 0)
615                         break;
616                 if (copy_from_user(&smi, p, sizeof(smi)))
617                         err2 = -EFAULT;
618                 else if (version == IPC_64)
619                         err2 = put_compat_shminfo64(&smi, uptr);
620                 else
621                         err2 = put_compat_shminfo(&smi, uptr);
622                 if (err2)
623                         err = -EFAULT;
624                 break;
625
626
627         case IPC_SET:
628                 if (version == IPC_64) {
629                         err = get_compat_shmid64_ds(&s64, uptr);
630                 } else {
631                         err = get_compat_shmid_ds(&s64, uptr);
632                 }
633                 if (err)
634                         break;
635                 p = compat_alloc_user_space(sizeof(s64));
636                 if (copy_to_user(p, &s64, sizeof(s64)))
637                         err = -EFAULT;
638                 else
639                         err = sys_shmctl(first, second, p);
640                 break;
641
642         case IPC_STAT:
643         case SHM_STAT:
644                 p = compat_alloc_user_space(sizeof(s64));
645                 err = sys_shmctl(first, second, p);
646                 if (err < 0)
647                         break;
648                 if (copy_from_user(&s64, p, sizeof(s64)))
649                         err2 = -EFAULT;
650                 else if (version == IPC_64)
651                         err2 = put_compat_shmid64_ds(&s64, uptr);
652                 else
653                         err2 = put_compat_shmid_ds(&s64, uptr);
654                 if (err2)
655                         err = -EFAULT;
656                 break;
657
658         case SHM_INFO:
659                 p = compat_alloc_user_space(sizeof(struct shm_info));
660                 err = sys_shmctl(first, second, p);
661                 if (err < 0)
662                         break;
663                 err2 = put_compat_shm_info(p, uptr);
664                 if (err2)
665                         err = -EFAULT;
666                 break;
667
668         default:
669                 err = -EINVAL;
670                 break;
671         }
672         return err;
673 }
674
675 long compat_sys_semtimedop(int semid, struct sembuf __user *tsems,
676                 unsigned nsops, const struct compat_timespec __user *timeout)
677 {
678         struct timespec __user *ts64 = NULL;
679         if (timeout) {
680                 struct timespec ts;
681                 ts64 = compat_alloc_user_space(sizeof(*ts64));
682                 if (get_compat_timespec(&ts, timeout))
683                         return -EFAULT;
684                 if (copy_to_user(ts64, &ts, sizeof(ts)))
685                         return -EFAULT;
686         }
687         return sys_semtimedop(semid, tsems, nsops, ts64);
688 }