1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2016, Joyent, Inc.
24 */
25
26 #ifndef _IPC_IMPL_H
27 #define _IPC_IMPL_H
28
29 #include <sys/types.h>
30 #include <sys/ipc.h>
31 #include <sys/mutex.h>
32 #include <sys/ipc_rctl.h>
33 #include <sys/project.h>
34 #include <sys/zone.h>
35 #include <sys/sysmacros.h>
36 #include <sys/avl.h>
37 #include <sys/id_space.h>
38 #include <sys/cred.h>
39 #include <sys/list.h>
40
41 #ifdef __cplusplus
42 extern "C" {
43 #endif
44
45 typedef uint64_t ipc_time_t;
46
47 /* For xxxctl64 */
48 #define IPC_SET64 13 /* set options */
49 #define IPC_STAT64 14 /* get options */
50
51 /*
52 * There are two versions of the userland ipc_perm structure:
53 * ipc_perm - the version used by user applications and by the kernel
54 * when the user and kernel data models match (in ipc.h)
55 * ipc_perm32 - the 64-bit kernel's view of a 32-bit struct ipc_perm
56 */
57 #if defined(_SYSCALL32)
58 struct ipc_perm32 {
59 uid32_t uid; /* owner's user id */
60 gid32_t gid; /* owner's group id */
61 uid32_t cuid; /* creator's user id */
62 gid32_t cgid; /* creator's group id */
63 mode32_t mode; /* access modes */
64 uint32_t seq; /* slot usage sequence number */
65 key32_t key; /* key */
66 int32_t pad[4]; /* reserve area */
67 };
68 #endif /* _SYSCALL32 */
69
70 /*
71 * This is the ipc_perm equivalent used in the xxxid_ds64 structures.
72 * It, like the structures it is used in, is intended only for use in
73 * communication between the kernel and user programs, and has the same
74 * layout across all data models.
75 *
76 * The xxxid_ds64 structures rely on ipc_perm64 being a multiple of
77 * 8 bytes so subsequent fields are 64-bit aligned on x86.
78 */
79 typedef struct ipc_perm64 {
80 uid_t ipcx_uid; /* owner's user id */
81 gid_t ipcx_gid; /* owner's group id */
82 uid_t ipcx_cuid; /* creator's user id */
83 gid_t ipcx_cgid; /* creator's group id */
84 mode_t ipcx_mode; /* access modes */
85 key_t ipcx_key; /* key */
86 projid_t ipcx_projid; /* allocating project id */
87 zoneid_t ipcx_zoneid; /* creator's zone id */
88 } ipc_perm64_t;
89
90 /*
91 * These are versions of xxxid_ds which are intended only for use in
92 * communication between the kernel and user programs, and therefore
93 * have the same layout across all data models. Omitted are all
94 * implementation-specific fields which would be of no use to user
95 * programs.
96 */
97 struct shmid_ds64 {
98 ipc_perm64_t shmx_perm; /* operation permission struct */
99 pid_t shmx_lpid; /* pid of last shmop */
100 pid_t shmx_cpid; /* pid of creator */
101 uint64_t shmx_segsz; /* size of segment in bytes */
102 uint64_t shmx_nattch; /* # of attaches */
103 uint64_t shmx_cnattch; /* # of ISM attaches */
104 uint64_t shmx_lkcnt; /* lock count ??? */
105 ipc_time_t shmx_atime; /* last shmat time */
106 ipc_time_t shmx_dtime; /* last shmdt time */
107 ipc_time_t shmx_ctime; /* last change time */
108 };
109
110 struct semid_ds64 {
111 ipc_perm64_t semx_perm; /* operation permission struct */
112 ushort_t semx_nsems; /* # of semaphores in set */
113 ushort_t _semx_pad[3]; /* pad to 8-byte multiple */
114 ipc_time_t semx_otime; /* last semop time */
115 ipc_time_t semx_ctime; /* last change time */
116 };
117
118 struct msqid_ds64 {
119 ipc_perm64_t msgx_perm; /* operation permission struct */
120 uint64_t msgx_cbytes; /* current # bytes on q */
121 uint64_t msgx_qnum; /* # of messages on q */
122 uint64_t msgx_qbytes; /* max # of bytes on q */
123 pid_t msgx_lspid; /* pid of last msgsnd */
124 pid_t msgx_lrpid; /* pid of last msgrcv */
125 ipc_time_t msgx_stime; /* last msgsnd time */
126 ipc_time_t msgx_rtime; /* last msgrcv time */
127 ipc_time_t msgx_ctime; /* last change time */
128 };
129
130 #ifdef _KERNEL
131
132 /*
133 * Implementation macros
134 */
135 #define IPC_FREE(x) (((x)->ipc_mode & IPC_ALLOC) == 0)
136
137 #define IPC_SEQ_BITS 7
138 #define IPC_SEQ_MASK ((1 << IPC_SEQ_BITS) - 1)
139 #define IPC_SEQ_SHIFT (31 - IPC_SEQ_BITS)
140 #define IPC_INDEX_MASK ((1 << IPC_SEQ_SHIFT) - 1)
141 #define IPC_SEQ(x) ((unsigned int)(x) >> IPC_SEQ_SHIFT)
142 #define IPC_INDEX(x) ((unsigned int)(x) & IPC_INDEX_MASK)
143
144 #define IPC_IDS_MIN (PAGESIZE / 64) /* starting # of entries */
145 #define IPC_IDS_MAX (1 << IPC_SEQ_SHIFT) /* maximum # of entries */
146 #define IPC_ID_INVAL UINT_MAX
147
148 #define IPC_PROJ_USAGE(p, s) \
149 (*(rctl_qty_t *)(((char *)&p->ipc_proj->kpj_data.kpd_ipc) + \
150 s->ipcs_rctlofs))
151 #define IPC_ZONE_USAGE(p, s) \
152 (*(rctl_qty_t *)(((char *)&p->ipc_zone_ref.zref_zone->zone_ipc) + \
153 s->ipcs_rctlofs))
154 #define IPC_LOCKED(s, o) \
155 MUTEX_HELD(&s->ipcs_table[IPC_INDEX(o->ipc_id)].ipct_lock)
156
157 /*
158 * The kernel's ipc_perm structure.
159 */
160 typedef struct kipc_perm {
161 avl_node_t ipc_avl; /* avl node if key is non-private */
162 list_node_t ipc_list; /* list node in list of all ids */
163 uint_t ipc_ref; /* reference count */
164 uid_t ipc_uid; /* owner's user id */
165 gid_t ipc_gid; /* owner's group id */
166 uid_t ipc_cuid; /* creator's user id */
167 gid_t ipc_cgid; /* creator's group id */
168 mode_t ipc_mode; /* access modes */
169 key_t ipc_key; /* key */
170 kproject_t *ipc_proj; /* creator's project */
171 uint_t ipc_id; /* id */
172 zoneid_t ipc_zoneid; /* creator's zone id */
173 zone_ref_t ipc_zone_ref; /* reference to creator's zone */
174 } kipc_perm_t;
175
176 typedef struct ipc_slot {
177 kmutex_t ipct_lock; /* bucket lock */
178 kipc_perm_t *ipct_data; /* data */
179 uint_t ipct_seq; /* sequence number */
180 struct ipc_slot *ipct_chain; /* for stale arrays */
181 char ipct_pad[64 - sizeof (kmutex_t) - 3 * sizeof (void *)];
182 } ipc_slot_t;
183
184 typedef void(ipc_func_t)(kipc_perm_t *);
185
186 typedef struct ipc_service {
187 kmutex_t ipcs_lock; /* lock for (de)allocation, keys */
188 avl_tree_t ipcs_keys; /* objects sorted by key */
189 ipc_slot_t *ipcs_table; /* table of objects */
190 uint_t ipcs_tabsz; /* size of table */
191 uint_t ipcs_count; /* # of objects allocated */
192 rctl_hndl_t ipcs_proj_rctl; /* id limiting rctl handle */
193 rctl_hndl_t ipcs_zone_rctl; /* id limiting rctl handle */
194 size_t ipcs_rctlofs; /* offset in kproject_data_t */
195 id_space_t *ipcs_ids; /* id space for objects */
196 size_t ipcs_ssize; /* object size (for allocation) */
197 ipc_func_t *ipcs_dtor; /* object destructor */
198 ipc_func_t *ipcs_rmid; /* object removal */
199 list_t ipcs_usedids; /* list of allocated ids */
200 int ipcs_atype; /* audit type (see c2/audit.h) */
201 } ipc_service_t;
202
203 int ipcperm_access(kipc_perm_t *, int, cred_t *);
204 int ipcperm_set(ipc_service_t *, struct cred *, kipc_perm_t *,
205 struct ipc_perm *, model_t);
206 void ipcperm_stat(struct ipc_perm *, kipc_perm_t *, model_t);
207 int ipcperm_set64(ipc_service_t *, struct cred *, kipc_perm_t *,
208 ipc_perm64_t *);
209 void ipcperm_stat64(ipc_perm64_t *, kipc_perm_t *);
210
211 ipc_service_t *ipcs_create(const char *, rctl_hndl_t, rctl_hndl_t, size_t,
212 ipc_func_t *, ipc_func_t *, int, size_t);
213 void ipcs_destroy(ipc_service_t *);
214 void ipcs_lock(ipc_service_t *);
215 void ipcs_unlock(ipc_service_t *);
216
217 kmutex_t *ipc_lock(ipc_service_t *, int);
218 kmutex_t *ipc_relock(ipc_service_t *, int, kmutex_t *);
219 kmutex_t *ipc_lookup(ipc_service_t *, int, kipc_perm_t **);
220
221 void ipc_hold(ipc_service_t *, kipc_perm_t *);
222 void ipc_rele(ipc_service_t *, kipc_perm_t *);
223 void ipc_rele_locked(ipc_service_t *, kipc_perm_t *);
224
225 int ipc_get(ipc_service_t *, key_t, int, kipc_perm_t **, kmutex_t **);
226 int ipc_commit_begin(ipc_service_t *, key_t, int, kipc_perm_t *);
227 kmutex_t *ipc_commit_end(ipc_service_t *, kipc_perm_t *);
228 void ipc_cleanup(ipc_service_t *, kipc_perm_t *);
229
230 void ipc_rmsvc(ipc_service_t *, kipc_perm_t *);
231 int ipc_rmid(ipc_service_t *, int, cred_t *);
232 int ipc_ids(ipc_service_t *, int *, uint_t, uint_t *);
233
234 void ipc_remove_zone(ipc_service_t *, zoneid_t);
235
236 #else /* _KERNEL */
237
238 int msgctl64(int, int, struct msqid_ds64 *);
239 int semctl64(int, int, int, ...);
240 int shmctl64(int, int, struct shmid_ds64 *);
241
242 #endif /* _KERNEL */
243
244
245 #ifdef __cplusplus
246 }
247 #endif
248
249 #endif /* _IPC_IMPL_H */