summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/sys/ipc_impl.h
blob: 0569c3e967198bbc68c9485c0614217d6f6f6ce7 (plain)
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
/*
 * 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.
 */

#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 *);

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 */