1 /* $NetBSD: linux_ipc.c,v 1.53 2009/04/23 17:40:57 njoly Exp $ */
4 * Copyright (c) 1995, 1998 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Frank van der Linden and Eric Haszlakiewicz.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: linux_ipc.c,v 1.53 2009/04/23 17:40:57 njoly Exp $");
35 #if defined(_KERNEL_OPT)
39 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/vnode.h>
47 #include <sys/mount.h>
48 #include <sys/syscallargs.h>
50 #include <compat/linux/common/linux_types.h>
51 #include <compat/linux/common/linux_signal.h>
52 #include <compat/linux/common/linux_util.h>
53 #include <compat/linux/common/linux_ipc.h>
54 #include <compat/linux/common/linux_msg.h>
55 #include <compat/linux/common/linux_shm.h>
56 #include <compat/linux/common/linux_sem.h>
58 #include <compat/linux/linux_syscallargs.h>
59 #include <compat/linux/linux_syscall.h>
61 #include <compat/linux/common/linux_ipccall.h>
62 #include <compat/linux/common/linux_machdep.h>
65 * Note: Not all linux architechtures have explicit versions
66 * of the SYSV* syscalls. On the ones that don't
67 * we pretend that they are defined anyway. *_args and
68 * prototypes are defined in individual headers;
69 * syscalls.master lists those syscalls as NOARGS.
71 * The functions in multiarch are the ones that just need
72 * the arguments shuffled around and then use the
73 * normal NetBSD syscall.
75 * Function in multiarch:
76 * linux_sys_ipc : linux_ipccall.c
77 * liunx_semop : linux_ipccall.c
78 * linux_semget : linux_ipccall.c
79 * linux_msgsnd : linux_ipccall.c
80 * linux_msgrcv : linux_ipccall.c
81 * linux_msgget : linux_ipccall.c
82 * linux_shmdt : linux_ipccall.c
83 * linux_shmget : linux_ipccall.c
86 #if defined (SYSVSEM) || defined(SYSVSHM) || defined(SYSVMSG)
88 * Convert between Linux and NetBSD ipc_perm structures. Only the
89 * order of the fields is different.
92 linux_to_bsd_ipc_perm(struct linux_ipc_perm
*lpp
, struct ipc_perm
*bpp
)
95 bpp
->_key
= lpp
->l_key
;
96 bpp
->uid
= lpp
->l_uid
;
97 bpp
->gid
= lpp
->l_gid
;
98 bpp
->cuid
= lpp
->l_cuid
;
99 bpp
->cgid
= lpp
->l_cgid
;
100 bpp
->mode
= lpp
->l_mode
;
101 bpp
->_seq
= lpp
->l_seq
;
105 linux_to_bsd_ipc64_perm(struct linux_ipc64_perm
*lpp
, struct ipc_perm
*bpp
)
107 bpp
->_key
= lpp
->l_key
;
108 bpp
->uid
= lpp
->l_uid
;
109 bpp
->gid
= lpp
->l_gid
;
110 bpp
->cuid
= lpp
->l_cuid
;
111 bpp
->cgid
= lpp
->l_cgid
;
112 bpp
->mode
= lpp
->l_mode
;
113 bpp
->_seq
= lpp
->l_seq
;
117 bsd_to_linux_ipc_perm(struct ipc_perm
*bpp
, struct linux_ipc_perm
*lpp
)
120 lpp
->l_key
= bpp
->_key
;
121 lpp
->l_uid
= bpp
->uid
;
122 lpp
->l_gid
= bpp
->gid
;
123 lpp
->l_cuid
= bpp
->cuid
;
124 lpp
->l_cgid
= bpp
->cgid
;
125 lpp
->l_mode
= bpp
->mode
;
126 lpp
->l_seq
= bpp
->_seq
;
130 bsd_to_linux_ipc64_perm(struct ipc_perm
*bpp
, struct linux_ipc64_perm
*lpp
)
132 lpp
->l_key
= bpp
->_key
;
133 lpp
->l_uid
= bpp
->uid
;
134 lpp
->l_gid
= bpp
->gid
;
135 lpp
->l_cuid
= bpp
->cuid
;
136 lpp
->l_cgid
= bpp
->cgid
;
137 lpp
->l_mode
= bpp
->mode
;
138 lpp
->l_seq
= bpp
->_seq
;
145 * Semaphore operations. Most constants and structures are the same on
146 * both systems. Only semctl() needs some extra work.
150 * Convert between Linux and NetBSD semid_ds structures.
153 bsd_to_linux_semid_ds(struct semid_ds
*bs
, struct linux_semid_ds
*ls
)
155 bsd_to_linux_ipc_perm(&bs
->sem_perm
, &ls
->l_sem_perm
);
156 ls
->l_sem_otime
= bs
->sem_otime
;
157 ls
->l_sem_ctime
= bs
->sem_ctime
;
158 ls
->l_sem_nsems
= bs
->sem_nsems
;
159 ls
->l_sem_base
= bs
->_sem_base
;
163 bsd_to_linux_semid64_ds(struct semid_ds
*bs
, struct linux_semid64_ds
*ls
)
165 bsd_to_linux_ipc64_perm(&bs
->sem_perm
, &ls
->l_sem_perm
);
166 ls
->l_sem_otime
= bs
->sem_otime
;
167 ls
->l_sem_ctime
= bs
->sem_ctime
;
168 ls
->l_sem_nsems
= bs
->sem_nsems
;
172 linux_to_bsd_semid_ds(struct linux_semid_ds
*ls
, struct semid_ds
*bs
)
174 linux_to_bsd_ipc_perm(&ls
->l_sem_perm
, &bs
->sem_perm
);
175 bs
->sem_otime
= ls
->l_sem_otime
;
176 bs
->sem_ctime
= ls
->l_sem_ctime
;
177 bs
->sem_nsems
= ls
->l_sem_nsems
;
178 bs
->_sem_base
= ls
->l_sem_base
;
182 linux_to_bsd_semid64_ds(struct linux_semid64_ds
*ls
, struct semid_ds
*bs
)
184 linux_to_bsd_ipc64_perm(&ls
->l_sem_perm
, &bs
->sem_perm
);
185 bs
->sem_otime
= ls
->l_sem_otime
;
186 bs
->sem_ctime
= ls
->l_sem_ctime
;
187 bs
->sem_nsems
= ls
->l_sem_nsems
;
191 * Most of this can be handled by directly passing the arguments on; we
192 * just need to frob the `cmd' and convert the semid_ds and semun.
195 linux_sys_semctl(struct lwp
*l
, const struct linux_sys_semctl_args
*uap
, register_t
*retval
)
198 syscallarg(int) semid;
199 syscallarg(int) semnum;
201 syscallarg(union linux_semun) arg;
203 struct semid_ds sembuf
;
204 struct linux_semid_ds lsembuf
;
205 struct linux_semid64_ds lsembuf64
;
207 int cmd
, lcmd
, error
;
208 void *pass_arg
= NULL
;
210 lcmd
= SCARG(uap
, cmd
);
211 #ifdef LINUX_IPC_FORCE64
212 lcmd
|= LINUX_IPC_64
;
215 switch (lcmd
& ~LINUX_IPC_64
) {
217 if (lcmd
& LINUX_IPC_64
) {
218 error
= copyin(SCARG(uap
, arg
).l_buf
, &lsembuf64
,
220 linux_to_bsd_semid64_ds(&lsembuf64
, &sembuf
);
222 error
= copyin(SCARG(uap
, arg
).l_buf
, &lsembuf
,
224 linux_to_bsd_semid_ds(&lsembuf
, &sembuf
);
259 semun
.array
= SCARG(uap
, arg
).l_array
;
265 semun
.val
= SCARG(uap
, arg
).l_val
;
271 semun
.array
= SCARG(uap
, arg
).l_array
;
279 error
= semctl1(l
, SCARG(uap
, semid
), SCARG(uap
, semnum
), cmd
,
286 bsd_to_linux_semid_ds(&sembuf
, &lsembuf
);
287 error
= copyout(&lsembuf
, SCARG(uap
, arg
).l_buf
,
290 case LINUX_IPC_STAT
| LINUX_IPC_64
:
291 bsd_to_linux_semid64_ds(&sembuf
, &lsembuf64
);
292 error
= copyout(&lsembuf64
, SCARG(uap
, arg
).l_buf
,
306 linux_to_bsd_msqid_ds(struct linux_msqid_ds
*lmp
, struct msqid_ds
*bmp
)
309 memset(bmp
, 0, sizeof(*bmp
));
310 linux_to_bsd_ipc_perm(&lmp
->l_msg_perm
, &bmp
->msg_perm
);
311 bmp
->_msg_first
= lmp
->l_msg_first
;
312 bmp
->_msg_last
= lmp
->l_msg_last
;
313 bmp
->_msg_cbytes
= lmp
->l_msg_cbytes
;
314 bmp
->msg_qnum
= lmp
->l_msg_qnum
;
315 bmp
->msg_qbytes
= lmp
->l_msg_qbytes
;
316 bmp
->msg_lspid
= lmp
->l_msg_lspid
;
317 bmp
->msg_lrpid
= lmp
->l_msg_lrpid
;
318 bmp
->msg_stime
= lmp
->l_msg_stime
;
319 bmp
->msg_rtime
= lmp
->l_msg_rtime
;
320 bmp
->msg_ctime
= lmp
->l_msg_ctime
;
324 linux_to_bsd_msqid64_ds(struct linux_msqid64_ds
*lmp
, struct msqid_ds
*bmp
)
327 memset(bmp
, 0, sizeof(*bmp
));
328 linux_to_bsd_ipc64_perm(&lmp
->l_msg_perm
, &bmp
->msg_perm
);
329 bmp
->msg_stime
= lmp
->l_msg_stime
;
330 bmp
->msg_rtime
= lmp
->l_msg_rtime
;
331 bmp
->msg_ctime
= lmp
->l_msg_ctime
;
332 bmp
->_msg_cbytes
= lmp
->l_msg_cbytes
;
333 bmp
->msg_qnum
= lmp
->l_msg_qnum
;
334 bmp
->msg_qbytes
= lmp
->l_msg_qbytes
;
335 bmp
->msg_lspid
= lmp
->l_msg_lspid
;
336 bmp
->msg_lrpid
= lmp
->l_msg_lrpid
;
340 bsd_to_linux_msqid_ds(struct msqid_ds
*bmp
, struct linux_msqid_ds
*lmp
)
343 memset(lmp
, 0, sizeof(*lmp
));
344 bsd_to_linux_ipc_perm(&bmp
->msg_perm
, &lmp
->l_msg_perm
);
345 lmp
->l_msg_first
= bmp
->_msg_first
;
346 lmp
->l_msg_last
= bmp
->_msg_last
;
347 lmp
->l_msg_cbytes
= bmp
->_msg_cbytes
;
348 lmp
->l_msg_qnum
= bmp
->msg_qnum
;
349 lmp
->l_msg_qbytes
= bmp
->msg_qbytes
;
350 lmp
->l_msg_lspid
= bmp
->msg_lspid
;
351 lmp
->l_msg_lrpid
= bmp
->msg_lrpid
;
352 lmp
->l_msg_stime
= bmp
->msg_stime
;
353 lmp
->l_msg_rtime
= bmp
->msg_rtime
;
354 lmp
->l_msg_ctime
= bmp
->msg_ctime
;
358 bsd_to_linux_msqid64_ds(struct msqid_ds
*bmp
, struct linux_msqid64_ds
*lmp
)
361 memset(lmp
, 0, sizeof(*lmp
));
362 bsd_to_linux_ipc64_perm(&bmp
->msg_perm
, &lmp
->l_msg_perm
);
363 lmp
->l_msg_stime
= bmp
->msg_stime
;
364 lmp
->l_msg_rtime
= bmp
->msg_rtime
;
365 lmp
->l_msg_ctime
= bmp
->msg_ctime
;
366 lmp
->l_msg_cbytes
= bmp
->_msg_cbytes
;
367 lmp
->l_msg_qnum
= bmp
->msg_qnum
;
368 lmp
->l_msg_qbytes
= bmp
->msg_qbytes
;
369 lmp
->l_msg_lspid
= bmp
->msg_lspid
;
370 lmp
->l_msg_lrpid
= bmp
->msg_lrpid
;
374 linux_sys_msgctl(struct lwp
*l
, const struct linux_sys_msgctl_args
*uap
, register_t
*retval
)
377 syscallarg(int) msqid;
379 syscallarg(struct linux_msqid_ds *) buf;
381 struct msqid_ds bm
, *bmp
= NULL
;
382 struct linux_msqid_ds lm
;
383 struct linux_msqid64_ds lm64
;
384 int cmd
, lcmd
, error
;
386 lcmd
= SCARG(uap
, cmd
);
387 #ifdef LINUX_IPC_FORCE64
388 lcmd
|= LINUX_IPC_64
;
391 switch (lcmd
& ~LINUX_IPC_64
) {
397 if (lcmd
& LINUX_IPC_64
) {
398 error
= copyin(SCARG(uap
, buf
), &lm64
, sizeof lm64
);
399 linux_to_bsd_msqid64_ds(&lm64
, &bm
);
401 error
= copyin(SCARG(uap
, buf
), &lm
, sizeof lm
);
402 linux_to_bsd_msqid_ds(&lm
, &bm
);
416 if ((error
= msgctl1(l
, SCARG(uap
, msqid
), cmd
, bmp
)))
421 bsd_to_linux_msqid_ds(&bm
, &lm
);
422 error
= copyout(&lm
, SCARG(uap
, buf
), sizeof lm
);
424 case LINUX_IPC_STAT
|LINUX_IPC_64
:
425 bsd_to_linux_msqid64_ds(&bm
, &lm64
);
426 error
= copyout(&lm64
, SCARG(uap
, buf
), sizeof lm64
);
438 * shmget(2). Just make sure the Linux-compatible shmat() semantics
439 * is enabled for the segment, so that shmat() succeeds even when
440 * the segment would be removed.
443 linux_sys_shmget(struct lwp
*l
, const struct linux_sys_shmget_args
*uap
, register_t
*retval
)
446 syscallarg(key_t) key;
447 syscallarg(size_t) size;
448 syscallarg(int) shmflg;
450 struct sys_shmget_args bsd_ua
;
452 SCARG(&bsd_ua
, key
) = SCARG(uap
, key
);
453 SCARG(&bsd_ua
, size
) = SCARG(uap
, size
);
454 SCARG(&bsd_ua
, shmflg
) = SCARG(uap
, shmflg
) | _SHM_RMLINGER
;
456 return sys_shmget(l
, &bsd_ua
, retval
);
460 * shmat(2). Very straightforward, except that Linux passes a pointer
461 * in which the return value is to be passed. This is subsequently
462 * handled by libc, apparently.
466 linux_sys_shmat(struct lwp
*l
, const struct linux_sys_shmat_args
*uap
, register_t
*retval
)
469 syscallarg(int) shmid;
470 syscallarg(void *) shmaddr;
471 syscallarg(int) shmflg;
472 syscallarg(u_long *) raddr;
476 if ((error
= sys_shmat(l
, (const void *)uap
, retval
)))
479 if ((error
= copyout(&retval
[0], SCARG(uap
, raddr
), sizeof retval
[0])))
485 #endif /* __amd64__ */
488 * Convert between Linux and NetBSD shmid_ds structures.
489 * The order of the fields is once again the difference, and
490 * we also need a place to store the internal data pointer
491 * in, which is unfortunately stored in this structure.
493 * We abuse a Linux internal field for that.
496 linux_to_bsd_shmid_ds(struct linux_shmid_ds
*lsp
, struct shmid_ds
*bsp
)
499 linux_to_bsd_ipc_perm(&lsp
->l_shm_perm
, &bsp
->shm_perm
);
500 bsp
->shm_segsz
= lsp
->l_shm_segsz
;
501 bsp
->shm_lpid
= lsp
->l_shm_lpid
;
502 bsp
->shm_cpid
= lsp
->l_shm_cpid
;
503 bsp
->shm_nattch
= lsp
->l_shm_nattch
;
504 bsp
->shm_atime
= lsp
->l_shm_atime
;
505 bsp
->shm_dtime
= lsp
->l_shm_dtime
;
506 bsp
->shm_ctime
= lsp
->l_shm_ctime
;
507 bsp
->_shm_internal
= lsp
->l_private2
; /* XXX Oh well. */
511 linux_to_bsd_shmid64_ds(struct linux_shmid64_ds
*lsp
, struct shmid_ds
*bsp
)
514 linux_to_bsd_ipc64_perm(&lsp
->l_shm_perm
, &bsp
->shm_perm
);
515 bsp
->shm_segsz
= lsp
->l_shm_segsz
;
516 bsp
->shm_lpid
= lsp
->l_shm_lpid
;
517 bsp
->shm_cpid
= lsp
->l_shm_cpid
;
518 bsp
->shm_nattch
= lsp
->l_shm_nattch
;
519 bsp
->shm_atime
= lsp
->l_shm_atime
;
520 bsp
->shm_dtime
= lsp
->l_shm_dtime
;
521 bsp
->shm_ctime
= lsp
->l_shm_ctime
;
522 bsp
->_shm_internal
= (void*)lsp
->l___unused5
; /* XXX Oh well. */
526 bsd_to_linux_shmid_ds(struct shmid_ds
*bsp
, struct linux_shmid_ds
*lsp
)
529 bsd_to_linux_ipc_perm(&bsp
->shm_perm
, &lsp
->l_shm_perm
);
530 lsp
->l_shm_segsz
= bsp
->shm_segsz
;
531 lsp
->l_shm_lpid
= bsp
->shm_lpid
;
532 lsp
->l_shm_cpid
= bsp
->shm_cpid
;
533 lsp
->l_shm_nattch
= bsp
->shm_nattch
;
534 lsp
->l_shm_atime
= bsp
->shm_atime
;
535 lsp
->l_shm_dtime
= bsp
->shm_dtime
;
536 lsp
->l_shm_ctime
= bsp
->shm_ctime
;
537 lsp
->l_private2
= bsp
->_shm_internal
; /* XXX */
541 bsd_to_linux_shmid64_ds(struct shmid_ds
*bsp
, struct linux_shmid64_ds
*lsp
)
543 bsd_to_linux_ipc64_perm(&bsp
->shm_perm
, &lsp
->l_shm_perm
);
544 lsp
->l_shm_segsz
= bsp
->shm_segsz
;
545 lsp
->l_shm_lpid
= bsp
->shm_lpid
;
546 lsp
->l_shm_cpid
= bsp
->shm_cpid
;
547 lsp
->l_shm_nattch
= bsp
->shm_nattch
;
548 lsp
->l_shm_atime
= bsp
->shm_atime
;
549 lsp
->l_shm_dtime
= bsp
->shm_dtime
;
550 lsp
->l_shm_ctime
= bsp
->shm_ctime
;
551 lsp
->l___unused5
= (u_long
)bsp
->_shm_internal
; /* XXX */
557 * The usual structure conversion and massaging is done.
560 linux_sys_shmctl(struct lwp
*l
, const struct linux_sys_shmctl_args
*uap
, register_t
*retval
)
563 syscallarg(int) shmid;
565 syscallarg(struct linux_shmid_ds *) buf;
568 struct linux_shmid_ds ls
;
569 struct linux_shmid64_ds ls64
;
570 struct linux_shminfo64 lsi64
;
571 struct linux_shm_info lsi
;
572 int error
, i
, cmd
, shmid
;
574 shmid
= SCARG(uap
, shmid
);
575 cmd
= SCARG(uap
, cmd
);
576 #ifdef LINUX_IPC_FORCE64
580 switch (cmd
& ~LINUX_IPC_64
) {
582 shmid
= IXSEQ_TO_IPCID(shmid
, shmsegs
[shmid
].shm_perm
);
587 error
= shmctl1(l
, shmid
, IPC_STAT
, &bs
);
590 if (cmd
& LINUX_IPC_64
) {
591 bsd_to_linux_shmid64_ds(&bs
, &ls64
);
592 error
= copyout(&ls64
, SCARG(uap
, buf
), sizeof ls64
);
594 bsd_to_linux_shmid_ds(&bs
, &ls
);
595 error
= copyout(&ls
, SCARG(uap
, buf
), sizeof ls
);
600 if (cmd
& LINUX_IPC_64
) {
601 error
= copyin(SCARG(uap
, buf
), &ls64
, sizeof ls64
);
602 linux_to_bsd_shmid64_ds(&ls64
, &bs
);
604 error
= copyin(SCARG(uap
, buf
), &ls
, sizeof ls
);
605 linux_to_bsd_shmid_ds(&ls
, &bs
);
609 return shmctl1(l
, shmid
, IPC_SET
, &bs
);
612 return shmctl1(l
, shmid
, IPC_RMID
, NULL
);
615 return shmctl1(l
, shmid
, SHM_LOCK
, NULL
);
617 case LINUX_SHM_UNLOCK
:
618 return shmctl1(l
, shmid
, SHM_UNLOCK
, NULL
);
621 memset(&lsi64
, 0, sizeof lsi64
);
622 lsi64
.l_shmmax
= shminfo
.shmmax
;
623 lsi64
.l_shmmin
= shminfo
.shmmin
;
624 lsi64
.l_shmmni
= shminfo
.shmmni
;
625 lsi64
.l_shmseg
= shminfo
.shmseg
;
626 lsi64
.l_shmall
= shminfo
.shmall
;
627 for (i
= shminfo
.shmmni
- 1; i
> 0; i
--)
628 if (shmsegs
[i
].shm_perm
.mode
& SHMSEG_ALLOCATED
)
631 return copyout(&lsi64
, SCARG(uap
, buf
), sizeof lsi64
);
634 (void)memset(&lsi
, 0, sizeof lsi
);
635 lsi
.l_used_ids
= shm_nused
;
636 for (i
= 0; i
< shminfo
.shmmni
; i
++)
637 if (shmsegs
[i
].shm_perm
.mode
& SHMSEG_ALLOCATED
)
639 round_page(shmsegs
[i
].shm_segsz
) /
643 lsi
.l_swap_attempts
= 0;
644 lsi
.l_swap_successes
= 0;
645 for (i
= shminfo
.shmmni
- 1; i
> 0; i
--)
646 if (shmsegs
[i
].shm_perm
.mode
& SHMSEG_ALLOCATED
)
649 return copyout(&lsi
, SCARG(uap
, buf
), sizeof lsi
);
653 printf("linux_sys_shmctl cmd %d\n", SCARG(uap
, cmd
));