OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [ipc/] [util.c] - Blame information for rev 1774

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * linux/ipc/util.c
3
 * Copyright (C) 1992 Krishna Balasubramanian
4
 *
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>
11
 */
12
 
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
 
23
#if defined(CONFIG_SYSVIPC)
24
 
25
#include "util.h"
26
 
27
/**
28
 *      ipc_init        -       initialise IPC subsystem
29
 *
30
 *      The various system5 IPC resources (semaphores, messages and shared
31
 *      memory are initialised
32
 */
33
 
34
void __init ipc_init (void)
35
{
36
        sem_init();
37
        msg_init();
38
        shm_init();
39
        return;
40
}
41
 
42
/**
43
 *      ipc_init_ids            -       initialise IPC identifiers
44
 *      @ids: Identifier set
45
 *      @size: Number of identifiers
46
 *
47
 *      Given a size for the ipc identifier range (limited below IPCMNI)
48
 *      set up the sequence range to use then allocate and initialise the
49
 *      array itself.
50
 */
51
 
52
void __init ipc_init_ids(struct ipc_ids* ids, int size)
53
{
54
        int i;
55
        sema_init(&ids->sem,1);
56
 
57
        if(size > IPCMNI)
58
                size = IPCMNI;
59
        ids->size = size;
60
        ids->in_use = 0;
61
        ids->max_id = -1;
62
        ids->seq = 0;
63
        {
64
                int seq_limit = INT_MAX/SEQ_MULTIPLIER;
65
                if(seq_limit > USHRT_MAX)
66
                        ids->seq_max = USHRT_MAX;
67
                 else
68
                        ids->seq_max = seq_limit;
69
        }
70
 
71
        ids->entries = ipc_alloc(sizeof(struct ipc_id)*size);
72
 
73
        if(ids->entries == NULL) {
74
                printk(KERN_ERR "ipc_init_ids() failed, ipc service disabled.\n");
75
                ids->size = 0;
76
        }
77
        ids->ary = SPIN_LOCK_UNLOCKED;
78
        for(i=0;i<ids->size;i++)
79
                ids->entries[i].p = NULL;
80
}
81
 
82
/**
83
 *      ipc_findkey     -       find a key in an ipc identifier set
84
 *      @ids: Identifier set
85
 *      @key: The key to find
86
 *
87
 *      Returns the identifier if found or -1 if not.
88
 */
89
 
90
int ipc_findkey(struct ipc_ids* ids, key_t key)
91
{
92
        int id;
93
        struct kern_ipc_perm* p;
94
 
95
        for (id = 0; id <= ids->max_id; id++) {
96
                p = ids->entries[id].p;
97
                if(p==NULL)
98
                        continue;
99
                if (key == p->key)
100
                        return id;
101
        }
102
        return -1;
103
}
104
 
105
static int grow_ary(struct ipc_ids* ids, int newsize)
106
{
107
        struct ipc_id* new;
108
        struct ipc_id* old;
109
        int i;
110
 
111
        if(newsize > IPCMNI)
112
                newsize = IPCMNI;
113
        if(newsize <= ids->size)
114
                return newsize;
115
 
116
        new = ipc_alloc(sizeof(struct ipc_id)*newsize);
117
        if(new == NULL)
118
                return ids->size;
119
        memcpy(new, ids->entries, sizeof(struct ipc_id)*ids->size);
120
        for(i=ids->size;i<newsize;i++) {
121
                new[i].p = NULL;
122
        }
123
        spin_lock(&ids->ary);
124
 
125
        old = ids->entries;
126
        ids->entries = new;
127
        i = ids->size;
128
        ids->size = newsize;
129
        spin_unlock(&ids->ary);
130
        ipc_free(old, sizeof(struct ipc_id)*i);
131
        return ids->size;
132
}
133
 
134
/**
135
 *      ipc_addid       -       add an IPC identifier
136
 *      @ids: IPC identifier set
137
 *      @new: new IPC permission set
138
 *      @size: new size limit for the id array
139
 *
140
 *      Add an entry 'new' to the IPC arrays. The permissions object is
141
 *      initialised and the first free entry is set up and the id assigned
142
 *      is returned. The list is returned in a locked state on success.
143
 *      On failure the list is not locked and -1 is returned.
144
 */
145
 
146
int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
147
{
148
        int id;
149
 
150
        size = grow_ary(ids,size);
151
        for (id = 0; id < size; id++) {
152
                if(ids->entries[id].p == NULL)
153
                        goto found;
154
        }
155
        return -1;
156
found:
157
        ids->in_use++;
158
        if (id > ids->max_id)
159
                ids->max_id = id;
160
 
161
        new->cuid = new->uid = current->euid;
162
        new->gid = new->cgid = current->egid;
163
 
164
        new->seq = ids->seq++;
165
        if(ids->seq > ids->seq_max)
166
                ids->seq = 0;
167
 
168
        spin_lock(&ids->ary);
169
        ids->entries[id].p = new;
170
        return id;
171
}
172
 
173
/**
174
 *      ipc_rmid        -       remove an IPC identifier
175
 *      @ids: identifier set
176
 *      @id: Identifier to remove
177
 *
178
 *      The identifier must be valid, and in use. The kernel will panic if
179
 *      fed an invalid identifier. The entry is removed and internal
180
 *      variables recomputed. The object associated with the identifier
181
 *      is returned.
182
 */
183
 
184
struct kern_ipc_perm* ipc_rmid(struct ipc_ids* ids, int id)
185
{
186
        struct kern_ipc_perm* p;
187
        int lid = id % SEQ_MULTIPLIER;
188
        if(lid >= ids->size)
189
                BUG();
190
        p = ids->entries[lid].p;
191
        ids->entries[lid].p = NULL;
192
        if(p==NULL)
193
                BUG();
194
        ids->in_use--;
195
 
196
        if (lid == ids->max_id) {
197
                do {
198
                        lid--;
199
                        if(lid == -1)
200
                                break;
201
                } while (ids->entries[lid].p == NULL);
202
                ids->max_id = lid;
203
        }
204
        return p;
205
}
206
 
207
/**
208
 *      ipc_alloc       -       allocate ipc space
209
 *      @size: size desired
210
 *
211
 *      Allocate memory from the appropriate pools and return a pointer to it.
212
 *      NULL is returned if the allocation fails
213
 */
214
 
215
void* ipc_alloc(int size)
216
{
217
        void* out;
218
        if(size > PAGE_SIZE)
219
                out = vmalloc(size);
220
        else
221
                out = kmalloc(size, GFP_KERNEL);
222
        return out;
223
}
224
 
225
/**
226
 *      ipc_free        -       free ipc space
227
 *      @ptr: pointer returned by ipc_alloc
228
 *      @size: size of block
229
 *
230
 *      Free a block created with ipc_alloc. The caller must know the size
231
 *      used in the allocation call.
232
 */
233
 
234
void ipc_free(void* ptr, int size)
235
{
236
        if(size > PAGE_SIZE)
237
                vfree(ptr);
238
        else
239
                kfree(ptr);
240
}
241
 
242
/**
243
 *      ipcperms        -       check IPC permissions
244
 *      @ipcp: IPC permission set
245
 *      @flag: desired permission set.
246
 *
247
 *      Check user, group, other permissions for access
248
 *      to ipc resources. return 0 if allowed
249
 */
250
 
251
int ipcperms (struct kern_ipc_perm *ipcp, short flag)
252
{       /* flag will most probably be 0 or S_...UGO from <linux/stat.h> */
253
        int requested_mode, granted_mode;
254
 
255
        requested_mode = (flag >> 6) | (flag >> 3) | flag;
256
        granted_mode = ipcp->mode;
257
        if (current->euid == ipcp->cuid || current->euid == ipcp->uid)
258
                granted_mode >>= 6;
259
        else if (in_group_p(ipcp->cgid) || in_group_p(ipcp->gid))
260
                granted_mode >>= 3;
261
        /* is there some bit set in requested_mode but not in granted_mode? */
262
        if ((requested_mode & ~granted_mode & 0007) &&
263
            !capable(CAP_IPC_OWNER))
264
                return -1;
265
 
266
        return 0;
267
}
268
 
269
/*
270
 * Functions to convert between the kern_ipc_perm structure and the
271
 * old/new ipc_perm structures
272
 */
273
 
274
/**
275
 *      kernel_to_ipc64_perm    -       convert kernel ipc permissions to user
276
 *      @in: kernel permissions
277
 *      @out: new style IPC permissions
278
 *
279
 *      Turn the kernel object 'in' into a set of permissions descriptions
280
 *      for returning to userspace (out).
281
 */
282
 
283
 
284
void kernel_to_ipc64_perm (struct kern_ipc_perm *in, struct ipc64_perm *out)
285
{
286
        out->key        = in->key;
287
        out->uid        = in->uid;
288
        out->gid        = in->gid;
289
        out->cuid       = in->cuid;
290
        out->cgid       = in->cgid;
291
        out->mode       = in->mode;
292
        out->seq        = in->seq;
293
}
294
 
295
/**
296
 *      ipc64_perm_to_ipc_perm  -       convert old ipc permissions to new
297
 *      @in: new style IPC permissions
298
 *      @out: old style IPC permissions
299
 *
300
 *      Turn the new style permissions object in into a compatibility
301
 *      object and store it into the 'out' pointer.
302
 */
303
 
304
void ipc64_perm_to_ipc_perm (struct ipc64_perm *in, struct ipc_perm *out)
305
{
306
        out->key        = in->key;
307
        out->uid        = NEW_TO_OLD_UID(in->uid);
308
        out->gid        = NEW_TO_OLD_GID(in->gid);
309
        out->cuid       = NEW_TO_OLD_UID(in->cuid);
310
        out->cgid       = NEW_TO_OLD_GID(in->cgid);
311
        out->mode       = in->mode;
312
        out->seq        = in->seq;
313
}
314
 
315
#if !defined(__ia64__) && !defined(__hppa__)
316
 
317
/**
318
 *      ipc_parse_version       -       IPC call version
319
 *      @cmd: pointer to command
320
 *
321
 *      Return IPC_64 for new style IPC and IPC_OLD for old style IPC.
322
 *      The cmd value is turned from an encoding command and version into
323
 *      just the command code.
324
 */
325
 
326
int ipc_parse_version (int *cmd)
327
{
328
#ifdef __x86_64__
329
        if (!(current->thread.flags & THREAD_IA32))
330
                return IPC_64;
331
#endif
332
        if (*cmd & IPC_64) {
333
                *cmd ^= IPC_64;
334
                return IPC_64;
335
        } else {
336
                return IPC_OLD;
337
        }
338
}
339
 
340
#endif /* __ia64__ */
341
 
342
#else
343
/*
344
 * Dummy functions when SYSV IPC isn't configured
345
 */
346
 
347
void sem_exit (void)
348
{
349
    return;
350
}
351
 
352
asmlinkage long sys_semget (key_t key, int nsems, int semflg)
353
{
354
        return -ENOSYS;
355
}
356
 
357
asmlinkage long sys_semop (int semid, struct sembuf *sops, unsigned nsops)
358
{
359
        return -ENOSYS;
360
}
361
 
362
asmlinkage long sys_semtimedop(int semid, struct sembuf *sops, unsigned nsops,
363
                               const struct timespec *timeout)
364
{
365
        return -ENOSYS;
366
}
367
 
368
asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg)
369
{
370
        return -ENOSYS;
371
}
372
 
373
asmlinkage long sys_msgget (key_t key, int msgflg)
374
{
375
        return -ENOSYS;
376
}
377
 
378
asmlinkage long sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg)
379
{
380
        return -ENOSYS;
381
}
382
 
383
asmlinkage long sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp,
384
                       int msgflg)
385
{
386
        return -ENOSYS;
387
}
388
 
389
asmlinkage long sys_msgctl (int msqid, int cmd, struct msqid_ds *buf)
390
{
391
        return -ENOSYS;
392
}
393
 
394
asmlinkage long sys_shmget (key_t key, size_t size, int shmflag)
395
{
396
        return -ENOSYS;
397
}
398
 
399
asmlinkage long sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *addr)
400
{
401
        return -ENOSYS;
402
}
403
 
404
asmlinkage long sys_shmdt (char *shmaddr)
405
{
406
        return -ENOSYS;
407
}
408
 
409
asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
410
{
411
        return -ENOSYS;
412
}
413
 
414
#endif /* CONFIG_SYSVIPC */

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.