[PATCH] make bio->bi_end_io() optional
[linux-2.6/history.git] / ipc / util.c
blob73b978baa1ec3c5c34371bb5b77365ce0d55ae28
1 /*
2 * linux/ipc/util.c
3 * Copyright (C) 1992 Krishna Balasubramanian
5 * Sep 1997 - Call suser() last after "normal" permission checks so we
6 * get BSD style process accounting right.
7 * Occurs in several places in the IPC code.
8 * Chris Evans, <chris@ferret.lmh.ox.ac.uk>
9 * Nov 1999 - ipc helper functions, unified SMP locking
10 * Manfred Spraul <manfreds@colorfullife.com>
13 #include <linux/config.h>
14 #include <linux/mm.h>
15 #include <linux/shm.h>
16 #include <linux/init.h>
17 #include <linux/msg.h>
18 #include <linux/smp_lock.h>
19 #include <linux/vmalloc.h>
20 #include <linux/slab.h>
21 #include <linux/highuid.h>
22 #include <linux/security.h>
24 #if defined(CONFIG_SYSVIPC)
26 #include "util.h"
28 /**
29 * ipc_init - initialise IPC subsystem
31 * The various system5 IPC resources (semaphores, messages and shared
32 * memory are initialised
35 void __init ipc_init (void)
37 sem_init();
38 msg_init();
39 shm_init();
40 return;
43 /**
44 * ipc_init_ids - initialise IPC identifiers
45 * @ids: Identifier set
46 * @size: Number of identifiers
48 * Given a size for the ipc identifier range (limited below IPCMNI)
49 * set up the sequence range to use then allocate and initialise the
50 * array itself.
53 void __init ipc_init_ids(struct ipc_ids* ids, int size)
55 int i;
56 sema_init(&ids->sem,1);
58 if(size > IPCMNI)
59 size = IPCMNI;
60 ids->size = size;
61 ids->in_use = 0;
62 ids->max_id = -1;
63 ids->seq = 0;
65 int seq_limit = INT_MAX/SEQ_MULTIPLIER;
66 if(seq_limit > USHRT_MAX)
67 ids->seq_max = USHRT_MAX;
68 else
69 ids->seq_max = seq_limit;
72 ids->entries = ipc_alloc(sizeof(struct ipc_id)*size);
74 if(ids->entries == NULL) {
75 printk(KERN_ERR "ipc_init_ids() failed, ipc service disabled.\n");
76 ids->size = 0;
78 ids->ary = SPIN_LOCK_UNLOCKED;
79 for(i=0;i<ids->size;i++)
80 ids->entries[i].p = NULL;
83 /**
84 * ipc_findkey - find a key in an ipc identifier set
85 * @ids: Identifier set
86 * @key: The key to find
88 * Returns the identifier if found or -1 if not.
91 int ipc_findkey(struct ipc_ids* ids, key_t key)
93 int id;
94 struct kern_ipc_perm* p;
96 for (id = 0; id <= ids->max_id; id++) {
97 p = ids->entries[id].p;
98 if(p==NULL)
99 continue;
100 if (key == p->key)
101 return id;
103 return -1;
106 static int grow_ary(struct ipc_ids* ids, int newsize)
108 struct ipc_id* new;
109 struct ipc_id* old;
110 int i;
112 if(newsize > IPCMNI)
113 newsize = IPCMNI;
114 if(newsize <= ids->size)
115 return newsize;
117 new = ipc_alloc(sizeof(struct ipc_id)*newsize);
118 if(new == NULL)
119 return ids->size;
120 memcpy(new, ids->entries, sizeof(struct ipc_id)*ids->size);
121 for(i=ids->size;i<newsize;i++) {
122 new[i].p = NULL;
124 spin_lock(&ids->ary);
126 old = ids->entries;
127 ids->entries = new;
128 i = ids->size;
129 ids->size = newsize;
130 spin_unlock(&ids->ary);
131 ipc_free(old, sizeof(struct ipc_id)*i);
132 return ids->size;
136 * ipc_addid - add an IPC identifier
137 * @ids: IPC identifier set
138 * @new: new IPC permission set
139 * @size: new size limit for the id array
141 * Add an entry 'new' to the IPC arrays. The permissions object is
142 * initialised and the first free entry is set up and the id assigned
143 * is returned. The list is returned in a locked state on success.
144 * On failure the list is not locked and -1 is returned.
147 int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
149 int id;
151 size = grow_ary(ids,size);
152 for (id = 0; id < size; id++) {
153 if(ids->entries[id].p == NULL)
154 goto found;
156 return -1;
157 found:
158 ids->in_use++;
159 if (id > ids->max_id)
160 ids->max_id = id;
162 new->cuid = new->uid = current->euid;
163 new->gid = new->cgid = current->egid;
165 new->seq = ids->seq++;
166 if(ids->seq > ids->seq_max)
167 ids->seq = 0;
169 spin_lock(&ids->ary);
170 ids->entries[id].p = new;
171 return id;
175 * ipc_rmid - remove an IPC identifier
176 * @ids: identifier set
177 * @id: Identifier to remove
179 * The identifier must be valid, and in use. The kernel will panic if
180 * fed an invalid identifier. The entry is removed and internal
181 * variables recomputed. The object associated with the identifier
182 * is returned.
185 struct kern_ipc_perm* ipc_rmid(struct ipc_ids* ids, int id)
187 struct kern_ipc_perm* p;
188 int lid = id % SEQ_MULTIPLIER;
189 if(lid >= ids->size)
190 BUG();
191 p = ids->entries[lid].p;
192 ids->entries[lid].p = NULL;
193 if(p==NULL)
194 BUG();
195 ids->in_use--;
197 if (lid == ids->max_id) {
198 do {
199 lid--;
200 if(lid == -1)
201 break;
202 } while (ids->entries[lid].p == NULL);
203 ids->max_id = lid;
205 return p;
209 * ipc_alloc - allocate ipc space
210 * @size: size desired
212 * Allocate memory from the appropriate pools and return a pointer to it.
213 * NULL is returned if the allocation fails
216 void* ipc_alloc(int size)
218 void* out;
219 if(size > PAGE_SIZE)
220 out = vmalloc(size);
221 else
222 out = kmalloc(size, GFP_KERNEL);
223 return out;
227 * ipc_free - free ipc space
228 * @ptr: pointer returned by ipc_alloc
229 * @size: size of block
231 * Free a block created with ipc_alloc. The caller must know the size
232 * used in the allocation call.
235 void ipc_free(void* ptr, int size)
237 if(size > PAGE_SIZE)
238 vfree(ptr);
239 else
240 kfree(ptr);
244 * ipcperms - check IPC permissions
245 * @ipcp: IPC permission set
246 * @flag: desired permission set.
248 * Check user, group, other permissions for access
249 * to ipc resources. return 0 if allowed
252 int ipcperms (struct kern_ipc_perm *ipcp, short flag)
253 { /* flag will most probably be 0 or S_...UGO from <linux/stat.h> */
254 int requested_mode, granted_mode;
256 requested_mode = (flag >> 6) | (flag >> 3) | flag;
257 granted_mode = ipcp->mode;
258 if (current->euid == ipcp->cuid || current->euid == ipcp->uid)
259 granted_mode >>= 6;
260 else if (in_group_p(ipcp->cgid) || in_group_p(ipcp->gid))
261 granted_mode >>= 3;
262 /* is there some bit set in requested_mode but not in granted_mode? */
263 if ((requested_mode & ~granted_mode & 0007) &&
264 !capable(CAP_IPC_OWNER))
265 return -1;
267 return security_ops->ipc_permission(ipcp, flag);
271 * Functions to convert between the kern_ipc_perm structure and the
272 * old/new ipc_perm structures
276 * kernel_to_ipc64_perm - convert kernel ipc permissions to user
277 * @in: kernel permissions
278 * @out: new style IPC permissions
280 * Turn the kernel object 'in' into a set of permissions descriptions
281 * for returning to userspace (out).
285 void kernel_to_ipc64_perm (struct kern_ipc_perm *in, struct ipc64_perm *out)
287 out->key = in->key;
288 out->uid = in->uid;
289 out->gid = in->gid;
290 out->cuid = in->cuid;
291 out->cgid = in->cgid;
292 out->mode = in->mode;
293 out->seq = in->seq;
297 * ipc64_perm_to_ipc_perm - convert old ipc permissions to new
298 * @in: new style IPC permissions
299 * @out: old style IPC permissions
301 * Turn the new style permissions object in into a compatibility
302 * object and store it into the 'out' pointer.
305 void ipc64_perm_to_ipc_perm (struct ipc64_perm *in, struct ipc_perm *out)
307 out->key = in->key;
308 out->uid = NEW_TO_OLD_UID(in->uid);
309 out->gid = NEW_TO_OLD_GID(in->gid);
310 out->cuid = NEW_TO_OLD_UID(in->cuid);
311 out->cgid = NEW_TO_OLD_GID(in->cgid);
312 out->mode = in->mode;
313 out->seq = in->seq;
316 #ifndef __ia64__
319 * ipc_parse_version - IPC call version
320 * @cmd: pointer to command
322 * Return IPC_64 for new style IPC and IPC_OLD for old style IPC.
323 * The cmd value is turned from an encoding command and version into
324 * just the command code.
327 int ipc_parse_version (int *cmd)
329 if (*cmd & IPC_64) {
330 *cmd ^= IPC_64;
331 return IPC_64;
332 } else {
333 return IPC_OLD;
337 #endif /* __ia64__ */
339 #else
341 * Dummy functions when SYSV IPC isn't configured
344 int copy_semundo(unsigned long clone_flags, struct task_struct *tsk)
346 return 0;
349 void exit_semundo(struct task_struct *tsk)
351 return;
355 void sem_exit (void)
357 return;
360 asmlinkage long sys_semget (key_t key, int nsems, int semflg)
362 return -ENOSYS;
365 asmlinkage long sys_semop (int semid, struct sembuf *sops, unsigned nsops)
367 return -ENOSYS;
370 asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg)
372 return -ENOSYS;
375 asmlinkage long sys_msgget (key_t key, int msgflg)
377 return -ENOSYS;
380 asmlinkage long sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg)
382 return -ENOSYS;
385 asmlinkage long sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp,
386 int msgflg)
388 return -ENOSYS;
391 asmlinkage long sys_msgctl (int msqid, int cmd, struct msqid_ds *buf)
393 return -ENOSYS;
396 asmlinkage long sys_shmget (key_t key, size_t size, int shmflag)
398 return -ENOSYS;
401 asmlinkage long sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *addr)
403 return -ENOSYS;
406 asmlinkage long sys_shmdt (char *shmaddr)
408 return -ENOSYS;
411 asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
413 return -ENOSYS;
416 #endif /* CONFIG_SYSVIPC */