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