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