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

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [ipc/] [shm.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * linux/ipc/shm.c
3
 * Copyright (C) 1992, 1993 Krishna Balasubramanian
4
 *       Many improvements/fixes by Bruno Haible.
5
 * Replaced `struct shm_desc' by `struct vm_area_struct', July 1994.
6
 * Fixed the shm swap deallocation (shm_unuse()), August 1998 Andrea Arcangeli.
7
 *
8
 * /proc/sysvipc/shm support (c) 1999 Dragos Acostachioaie <dragos@iname.com>
9
 * BIGMEM support, Andrea Arcangeli <andrea@suse.de>
10
 * SMP thread shm, Jean-Luc Boyard <jean-luc.boyard@siemens.fr>
11
 * HIGHMEM support, Ingo Molnar <mingo@redhat.com>
12
 * Make shmmax, shmall, shmmni sysctl'able, Christoph Rohland <cr@sap.com>
13
 * Shared /dev/zero support, Kanoj Sarcar <kanoj@sgi.com>
14
 * Move the mm functionality over to mm/shmem.c, Christoph Rohland <cr@sap.com>
15
 *
16
 * support for audit of ipc object properties and permission changes
17
 * Dustin Kirkland <dustin.kirkland@us.ibm.com>
18
 *
19
 * namespaces support
20
 * OpenVZ, SWsoft Inc.
21
 * Pavel Emelianov <xemul@openvz.org>
22
 */
23
 
24
#include <linux/slab.h>
25
#include <linux/mm.h>
26
#include <linux/hugetlb.h>
27
#include <linux/shm.h>
28
#include <linux/init.h>
29
#include <linux/file.h>
30
#include <linux/mman.h>
31
#include <linux/shmem_fs.h>
32
#include <linux/security.h>
33
#include <linux/syscalls.h>
34
#include <linux/audit.h>
35
#include <linux/capability.h>
36
#include <linux/ptrace.h>
37
#include <linux/seq_file.h>
38
#include <linux/rwsem.h>
39
#include <linux/nsproxy.h>
40
#include <linux/mount.h>
41
 
42
#include <asm/uaccess.h>
43
 
44
#include "util.h"
45
 
46
struct shm_file_data {
47
        int id;
48
        struct ipc_namespace *ns;
49
        struct file *file;
50
        const struct vm_operations_struct *vm_ops;
51
};
52
 
53
#define shm_file_data(file) (*((struct shm_file_data **)&(file)->private_data))
54
 
55
static const struct file_operations shm_file_operations;
56
static struct vm_operations_struct shm_vm_ops;
57
 
58
static struct ipc_ids init_shm_ids;
59
 
60
#define shm_ids(ns)     (*((ns)->ids[IPC_SHM_IDS]))
61
 
62
#define shm_unlock(shp)                 \
63
        ipc_unlock(&(shp)->shm_perm)
64
#define shm_buildid(id, seq)    ipc_buildid(id, seq)
65
 
66
static int newseg(struct ipc_namespace *, struct ipc_params *);
67
static void shm_open(struct vm_area_struct *vma);
68
static void shm_close(struct vm_area_struct *vma);
69
static void shm_destroy (struct ipc_namespace *ns, struct shmid_kernel *shp);
70
#ifdef CONFIG_PROC_FS
71
static int sysvipc_shm_proc_show(struct seq_file *s, void *it);
72
#endif
73
 
74
static void __shm_init_ns(struct ipc_namespace *ns, struct ipc_ids *ids)
75
{
76
        ns->ids[IPC_SHM_IDS] = ids;
77
        ns->shm_ctlmax = SHMMAX;
78
        ns->shm_ctlall = SHMALL;
79
        ns->shm_ctlmni = SHMMNI;
80
        ns->shm_tot = 0;
81
        ipc_init_ids(ids);
82
}
83
 
84
/*
85
 * Called with shm_ids.rw_mutex (writer) and the shp structure locked.
86
 * Only shm_ids.rw_mutex remains locked on exit.
87
 */
88
static void do_shm_rmid(struct ipc_namespace *ns, struct shmid_kernel *shp)
89
{
90
        if (shp->shm_nattch){
91
                shp->shm_perm.mode |= SHM_DEST;
92
                /* Do not find it any more */
93
                shp->shm_perm.key = IPC_PRIVATE;
94
                shm_unlock(shp);
95
        } else
96
                shm_destroy(ns, shp);
97
}
98
 
99
int shm_init_ns(struct ipc_namespace *ns)
100
{
101
        struct ipc_ids *ids;
102
 
103
        ids = kmalloc(sizeof(struct ipc_ids), GFP_KERNEL);
104
        if (ids == NULL)
105
                return -ENOMEM;
106
 
107
        __shm_init_ns(ns, ids);
108
        return 0;
109
}
110
 
111
void shm_exit_ns(struct ipc_namespace *ns)
112
{
113
        struct shmid_kernel *shp;
114
        int next_id;
115
        int total, in_use;
116
 
117
        down_write(&shm_ids(ns).rw_mutex);
118
 
119
        in_use = shm_ids(ns).in_use;
120
 
121
        for (total = 0, next_id = 0; total < in_use; next_id++) {
122
                shp = idr_find(&shm_ids(ns).ipcs_idr, next_id);
123
                if (shp == NULL)
124
                        continue;
125
                ipc_lock_by_ptr(&shp->shm_perm);
126
                do_shm_rmid(ns, shp);
127
                total++;
128
        }
129
        up_write(&shm_ids(ns).rw_mutex);
130
 
131
        kfree(ns->ids[IPC_SHM_IDS]);
132
        ns->ids[IPC_SHM_IDS] = NULL;
133
}
134
 
135
void __init shm_init (void)
136
{
137
        __shm_init_ns(&init_ipc_ns, &init_shm_ids);
138
        ipc_init_proc_interface("sysvipc/shm",
139
                                "       key      shmid perms       size  cpid  lpid nattch   uid   gid  cuid  cgid      atime      dtime      ctime\n",
140
                                IPC_SHM_IDS, sysvipc_shm_proc_show);
141
}
142
 
143
/*
144
 * shm_lock_(check_)down routines are called in the paths where the rw_mutex
145
 * is held to protect access to the idr tree.
146
 */
147
static inline struct shmid_kernel *shm_lock_down(struct ipc_namespace *ns,
148
                                                int id)
149
{
150
        struct kern_ipc_perm *ipcp = ipc_lock_down(&shm_ids(ns), id);
151
 
152
        return container_of(ipcp, struct shmid_kernel, shm_perm);
153
}
154
 
155
static inline struct shmid_kernel *shm_lock_check_down(
156
                                                struct ipc_namespace *ns,
157
                                                int id)
158
{
159
        struct kern_ipc_perm *ipcp = ipc_lock_check_down(&shm_ids(ns), id);
160
 
161
        return container_of(ipcp, struct shmid_kernel, shm_perm);
162
}
163
 
164
/*
165
 * shm_lock_(check_) routines are called in the paths where the rw_mutex
166
 * is not held.
167
 */
168
static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id)
169
{
170
        struct kern_ipc_perm *ipcp = ipc_lock(&shm_ids(ns), id);
171
 
172
        return container_of(ipcp, struct shmid_kernel, shm_perm);
173
}
174
 
175
static inline struct shmid_kernel *shm_lock_check(struct ipc_namespace *ns,
176
                                                int id)
177
{
178
        struct kern_ipc_perm *ipcp = ipc_lock_check(&shm_ids(ns), id);
179
 
180
        return container_of(ipcp, struct shmid_kernel, shm_perm);
181
}
182
 
183
static inline void shm_rmid(struct ipc_namespace *ns, struct shmid_kernel *s)
184
{
185
        ipc_rmid(&shm_ids(ns), &s->shm_perm);
186
}
187
 
188
static inline int shm_addid(struct ipc_namespace *ns, struct shmid_kernel *shp)
189
{
190
        return ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni);
191
}
192
 
193
 
194
 
195
/* This is called by fork, once for every shm attach. */
196
static void shm_open(struct vm_area_struct *vma)
197
{
198
        struct file *file = vma->vm_file;
199
        struct shm_file_data *sfd = shm_file_data(file);
200
        struct shmid_kernel *shp;
201
 
202
        shp = shm_lock(sfd->ns, sfd->id);
203
        BUG_ON(IS_ERR(shp));
204
        shp->shm_atim = get_seconds();
205
        shp->shm_lprid = task_tgid_vnr(current);
206
        shp->shm_nattch++;
207
        shm_unlock(shp);
208
}
209
 
210
/*
211
 * shm_destroy - free the struct shmid_kernel
212
 *
213
 * @ns: namespace
214
 * @shp: struct to free
215
 *
216
 * It has to be called with shp and shm_ids.rw_mutex (writer) locked,
217
 * but returns with shp unlocked and freed.
218
 */
219
static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp)
220
{
221
        ns->shm_tot -= (shp->shm_segsz + PAGE_SIZE - 1) >> PAGE_SHIFT;
222
        shm_rmid(ns, shp);
223
        shm_unlock(shp);
224
        if (!is_file_hugepages(shp->shm_file))
225
                shmem_lock(shp->shm_file, 0, shp->mlock_user);
226
        else
227
                user_shm_unlock(shp->shm_file->f_path.dentry->d_inode->i_size,
228
                                                shp->mlock_user);
229
        fput (shp->shm_file);
230
        security_shm_free(shp);
231
        ipc_rcu_putref(shp);
232
}
233
 
234
/*
235
 * remove the attach descriptor vma.
236
 * free memory for segment if it is marked destroyed.
237
 * The descriptor has already been removed from the current->mm->mmap list
238
 * and will later be kfree()d.
239
 */
240
static void shm_close(struct vm_area_struct *vma)
241
{
242
        struct file * file = vma->vm_file;
243
        struct shm_file_data *sfd = shm_file_data(file);
244
        struct shmid_kernel *shp;
245
        struct ipc_namespace *ns = sfd->ns;
246
 
247
        down_write(&shm_ids(ns).rw_mutex);
248
        /* remove from the list of attaches of the shm segment */
249
        shp = shm_lock_down(ns, sfd->id);
250
        BUG_ON(IS_ERR(shp));
251
        shp->shm_lprid = task_tgid_vnr(current);
252
        shp->shm_dtim = get_seconds();
253
        shp->shm_nattch--;
254
        if(shp->shm_nattch == 0 &&
255
           shp->shm_perm.mode & SHM_DEST)
256
                shm_destroy(ns, shp);
257
        else
258
                shm_unlock(shp);
259
        up_write(&shm_ids(ns).rw_mutex);
260
}
261
 
262
static int shm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
263
{
264
        struct file *file = vma->vm_file;
265
        struct shm_file_data *sfd = shm_file_data(file);
266
 
267
        return sfd->vm_ops->fault(vma, vmf);
268
}
269
 
270
#ifdef CONFIG_NUMA
271
static int shm_set_policy(struct vm_area_struct *vma, struct mempolicy *new)
272
{
273
        struct file *file = vma->vm_file;
274
        struct shm_file_data *sfd = shm_file_data(file);
275
        int err = 0;
276
        if (sfd->vm_ops->set_policy)
277
                err = sfd->vm_ops->set_policy(vma, new);
278
        return err;
279
}
280
 
281
static struct mempolicy *shm_get_policy(struct vm_area_struct *vma,
282
                                        unsigned long addr)
283
{
284
        struct file *file = vma->vm_file;
285
        struct shm_file_data *sfd = shm_file_data(file);
286
        struct mempolicy *pol = NULL;
287
 
288
        if (sfd->vm_ops->get_policy)
289
                pol = sfd->vm_ops->get_policy(vma, addr);
290
        else if (vma->vm_policy)
291
                pol = vma->vm_policy;
292
        else
293
                pol = current->mempolicy;
294
        return pol;
295
}
296
#endif
297
 
298
static int shm_mmap(struct file * file, struct vm_area_struct * vma)
299
{
300
        struct shm_file_data *sfd = shm_file_data(file);
301
        int ret;
302
 
303
        ret = sfd->file->f_op->mmap(sfd->file, vma);
304
        if (ret != 0)
305
                return ret;
306
        sfd->vm_ops = vma->vm_ops;
307
#ifdef CONFIG_MMU
308
        BUG_ON(!sfd->vm_ops->fault);
309
#endif
310
        vma->vm_ops = &shm_vm_ops;
311
        shm_open(vma);
312
 
313
        return ret;
314
}
315
 
316
static int shm_release(struct inode *ino, struct file *file)
317
{
318
        struct shm_file_data *sfd = shm_file_data(file);
319
 
320
        put_ipc_ns(sfd->ns);
321
        shm_file_data(file) = NULL;
322
        kfree(sfd);
323
        return 0;
324
}
325
 
326
static int shm_fsync(struct file *file, struct dentry *dentry, int datasync)
327
{
328
        int (*fsync) (struct file *, struct dentry *, int datasync);
329
        struct shm_file_data *sfd = shm_file_data(file);
330
        int ret = -EINVAL;
331
 
332
        fsync = sfd->file->f_op->fsync;
333
        if (fsync)
334
                ret = fsync(sfd->file, sfd->file->f_path.dentry, datasync);
335
        return ret;
336
}
337
 
338
static unsigned long shm_get_unmapped_area(struct file *file,
339
        unsigned long addr, unsigned long len, unsigned long pgoff,
340
        unsigned long flags)
341
{
342
        struct shm_file_data *sfd = shm_file_data(file);
343
        return get_unmapped_area(sfd->file, addr, len, pgoff, flags);
344
}
345
 
346
int is_file_shm_hugepages(struct file *file)
347
{
348
        int ret = 0;
349
 
350
        if (file->f_op == &shm_file_operations) {
351
                struct shm_file_data *sfd;
352
                sfd = shm_file_data(file);
353
                ret = is_file_hugepages(sfd->file);
354
        }
355
        return ret;
356
}
357
 
358
static const struct file_operations shm_file_operations = {
359
        .mmap           = shm_mmap,
360
        .fsync          = shm_fsync,
361
        .release        = shm_release,
362
        .get_unmapped_area      = shm_get_unmapped_area,
363
};
364
 
365
static struct vm_operations_struct shm_vm_ops = {
366
        .open   = shm_open,     /* callback for a new vm-area open */
367
        .close  = shm_close,    /* callback for when the vm-area is released */
368
        .fault  = shm_fault,
369
#if defined(CONFIG_NUMA)
370
        .set_policy = shm_set_policy,
371
        .get_policy = shm_get_policy,
372
#endif
373
};
374
 
375
/**
376
 * newseg - Create a new shared memory segment
377
 * @ns: namespace
378
 * @params: ptr to the structure that contains key, size and shmflg
379
 *
380
 * Called with shm_ids.rw_mutex held as a writer.
381
 */
382
 
383
static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
384
{
385
        key_t key = params->key;
386
        int shmflg = params->flg;
387
        size_t size = params->u.size;
388
        int error;
389
        struct shmid_kernel *shp;
390
        int numpages = (size + PAGE_SIZE -1) >> PAGE_SHIFT;
391
        struct file * file;
392
        char name[13];
393
        int id;
394
 
395
        if (size < SHMMIN || size > ns->shm_ctlmax)
396
                return -EINVAL;
397
 
398
        if (ns->shm_tot + numpages > ns->shm_ctlall)
399
                return -ENOSPC;
400
 
401
        shp = ipc_rcu_alloc(sizeof(*shp));
402
        if (!shp)
403
                return -ENOMEM;
404
 
405
        shp->shm_perm.key = key;
406
        shp->shm_perm.mode = (shmflg & S_IRWXUGO);
407
        shp->mlock_user = NULL;
408
 
409
        shp->shm_perm.security = NULL;
410
        error = security_shm_alloc(shp);
411
        if (error) {
412
                ipc_rcu_putref(shp);
413
                return error;
414
        }
415
 
416
        sprintf (name, "SYSV%08x", key);
417
        if (shmflg & SHM_HUGETLB) {
418
                /* hugetlb_file_setup takes care of mlock user accounting */
419
                file = hugetlb_file_setup(name, size);
420
                shp->mlock_user = current->user;
421
        } else {
422
                int acctflag = VM_ACCOUNT;
423
                /*
424
                 * Do not allow no accounting for OVERCOMMIT_NEVER, even
425
                 * if it's asked for.
426
                 */
427
                if  ((shmflg & SHM_NORESERVE) &&
428
                                sysctl_overcommit_memory != OVERCOMMIT_NEVER)
429
                        acctflag = 0;
430
                file = shmem_file_setup(name, size, acctflag);
431
        }
432
        error = PTR_ERR(file);
433
        if (IS_ERR(file))
434
                goto no_file;
435
 
436
        id = shm_addid(ns, shp);
437
        if (id < 0) {
438
                error = id;
439
                goto no_id;
440
        }
441
 
442
        shp->shm_cprid = task_tgid_vnr(current);
443
        shp->shm_lprid = 0;
444
        shp->shm_atim = shp->shm_dtim = 0;
445
        shp->shm_ctim = get_seconds();
446
        shp->shm_segsz = size;
447
        shp->shm_nattch = 0;
448
        shp->shm_perm.id = shm_buildid(id, shp->shm_perm.seq);
449
        shp->shm_file = file;
450
        /*
451
         * shmid gets reported as "inode#" in /proc/pid/maps.
452
         * proc-ps tools use this. Changing this will break them.
453
         */
454
        file->f_dentry->d_inode->i_ino = shp->shm_perm.id;
455
 
456
        ns->shm_tot += numpages;
457
        error = shp->shm_perm.id;
458
        shm_unlock(shp);
459
        return error;
460
 
461
no_id:
462
        fput(file);
463
no_file:
464
        security_shm_free(shp);
465
        ipc_rcu_putref(shp);
466
        return error;
467
}
468
 
469
/*
470
 * Called with shm_ids.rw_mutex and ipcp locked.
471
 */
472
static inline int shm_security(struct kern_ipc_perm *ipcp, int shmflg)
473
{
474
        struct shmid_kernel *shp;
475
 
476
        shp = container_of(ipcp, struct shmid_kernel, shm_perm);
477
        return security_shm_associate(shp, shmflg);
478
}
479
 
480
/*
481
 * Called with shm_ids.rw_mutex and ipcp locked.
482
 */
483
static inline int shm_more_checks(struct kern_ipc_perm *ipcp,
484
                                struct ipc_params *params)
485
{
486
        struct shmid_kernel *shp;
487
 
488
        shp = container_of(ipcp, struct shmid_kernel, shm_perm);
489
        if (shp->shm_segsz < params->u.size)
490
                return -EINVAL;
491
 
492
        return 0;
493
}
494
 
495
asmlinkage long sys_shmget (key_t key, size_t size, int shmflg)
496
{
497
        struct ipc_namespace *ns;
498
        struct ipc_ops shm_ops;
499
        struct ipc_params shm_params;
500
 
501
        ns = current->nsproxy->ipc_ns;
502
 
503
        shm_ops.getnew = newseg;
504
        shm_ops.associate = shm_security;
505
        shm_ops.more_checks = shm_more_checks;
506
 
507
        shm_params.key = key;
508
        shm_params.flg = shmflg;
509
        shm_params.u.size = size;
510
 
511
        return ipcget(ns, &shm_ids(ns), &shm_ops, &shm_params);
512
}
513
 
514
static inline unsigned long copy_shmid_to_user(void __user *buf, struct shmid64_ds *in, int version)
515
{
516
        switch(version) {
517
        case IPC_64:
518
                return copy_to_user(buf, in, sizeof(*in));
519
        case IPC_OLD:
520
            {
521
                struct shmid_ds out;
522
 
523
                ipc64_perm_to_ipc_perm(&in->shm_perm, &out.shm_perm);
524
                out.shm_segsz   = in->shm_segsz;
525
                out.shm_atime   = in->shm_atime;
526
                out.shm_dtime   = in->shm_dtime;
527
                out.shm_ctime   = in->shm_ctime;
528
                out.shm_cpid    = in->shm_cpid;
529
                out.shm_lpid    = in->shm_lpid;
530
                out.shm_nattch  = in->shm_nattch;
531
 
532
                return copy_to_user(buf, &out, sizeof(out));
533
            }
534
        default:
535
                return -EINVAL;
536
        }
537
}
538
 
539
struct shm_setbuf {
540
        uid_t   uid;
541
        gid_t   gid;
542
        mode_t  mode;
543
};
544
 
545
static inline unsigned long copy_shmid_from_user(struct shm_setbuf *out, void __user *buf, int version)
546
{
547
        switch(version) {
548
        case IPC_64:
549
            {
550
                struct shmid64_ds tbuf;
551
 
552
                if (copy_from_user(&tbuf, buf, sizeof(tbuf)))
553
                        return -EFAULT;
554
 
555
                out->uid        = tbuf.shm_perm.uid;
556
                out->gid        = tbuf.shm_perm.gid;
557
                out->mode       = tbuf.shm_perm.mode;
558
 
559
                return 0;
560
            }
561
        case IPC_OLD:
562
            {
563
                struct shmid_ds tbuf_old;
564
 
565
                if (copy_from_user(&tbuf_old, buf, sizeof(tbuf_old)))
566
                        return -EFAULT;
567
 
568
                out->uid        = tbuf_old.shm_perm.uid;
569
                out->gid        = tbuf_old.shm_perm.gid;
570
                out->mode       = tbuf_old.shm_perm.mode;
571
 
572
                return 0;
573
            }
574
        default:
575
                return -EINVAL;
576
        }
577
}
578
 
579
static inline unsigned long copy_shminfo_to_user(void __user *buf, struct shminfo64 *in, int version)
580
{
581
        switch(version) {
582
        case IPC_64:
583
                return copy_to_user(buf, in, sizeof(*in));
584
        case IPC_OLD:
585
            {
586
                struct shminfo out;
587
 
588
                if(in->shmmax > INT_MAX)
589
                        out.shmmax = INT_MAX;
590
                else
591
                        out.shmmax = (int)in->shmmax;
592
 
593
                out.shmmin      = in->shmmin;
594
                out.shmmni      = in->shmmni;
595
                out.shmseg      = in->shmseg;
596
                out.shmall      = in->shmall;
597
 
598
                return copy_to_user(buf, &out, sizeof(out));
599
            }
600
        default:
601
                return -EINVAL;
602
        }
603
}
604
 
605
/*
606
 * Called with shm_ids.rw_mutex held as a reader
607
 */
608
static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss,
609
                unsigned long *swp)
610
{
611
        int next_id;
612
        int total, in_use;
613
 
614
        *rss = 0;
615
        *swp = 0;
616
 
617
        in_use = shm_ids(ns).in_use;
618
 
619
        for (total = 0, next_id = 0; total < in_use; next_id++) {
620
                struct shmid_kernel *shp;
621
                struct inode *inode;
622
 
623
                shp = idr_find(&shm_ids(ns).ipcs_idr, next_id);
624
                if (shp == NULL)
625
                        continue;
626
 
627
                inode = shp->shm_file->f_path.dentry->d_inode;
628
 
629
                if (is_file_hugepages(shp->shm_file)) {
630
                        struct address_space *mapping = inode->i_mapping;
631
                        *rss += (HPAGE_SIZE/PAGE_SIZE)*mapping->nrpages;
632
                } else {
633
                        struct shmem_inode_info *info = SHMEM_I(inode);
634
                        spin_lock(&info->lock);
635
                        *rss += inode->i_mapping->nrpages;
636
                        *swp += info->swapped;
637
                        spin_unlock(&info->lock);
638
                }
639
 
640
                total++;
641
        }
642
}
643
 
644
asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
645
{
646
        struct shm_setbuf setbuf;
647
        struct shmid_kernel *shp;
648
        int err, version;
649
        struct ipc_namespace *ns;
650
 
651
        if (cmd < 0 || shmid < 0) {
652
                err = -EINVAL;
653
                goto out;
654
        }
655
 
656
        version = ipc_parse_version(&cmd);
657
        ns = current->nsproxy->ipc_ns;
658
 
659
        switch (cmd) { /* replace with proc interface ? */
660
        case IPC_INFO:
661
        {
662
                struct shminfo64 shminfo;
663
 
664
                err = security_shm_shmctl(NULL, cmd);
665
                if (err)
666
                        return err;
667
 
668
                memset(&shminfo,0,sizeof(shminfo));
669
                shminfo.shmmni = shminfo.shmseg = ns->shm_ctlmni;
670
                shminfo.shmmax = ns->shm_ctlmax;
671
                shminfo.shmall = ns->shm_ctlall;
672
 
673
                shminfo.shmmin = SHMMIN;
674
                if(copy_shminfo_to_user (buf, &shminfo, version))
675
                        return -EFAULT;
676
 
677
                down_read(&shm_ids(ns).rw_mutex);
678
                err = ipc_get_maxid(&shm_ids(ns));
679
                up_read(&shm_ids(ns).rw_mutex);
680
 
681
                if(err<0)
682
                        err = 0;
683
                goto out;
684
        }
685
        case SHM_INFO:
686
        {
687
                struct shm_info shm_info;
688
 
689
                err = security_shm_shmctl(NULL, cmd);
690
                if (err)
691
                        return err;
692
 
693
                memset(&shm_info,0,sizeof(shm_info));
694
                down_read(&shm_ids(ns).rw_mutex);
695
                shm_info.used_ids = shm_ids(ns).in_use;
696
                shm_get_stat (ns, &shm_info.shm_rss, &shm_info.shm_swp);
697
                shm_info.shm_tot = ns->shm_tot;
698
                shm_info.swap_attempts = 0;
699
                shm_info.swap_successes = 0;
700
                err = ipc_get_maxid(&shm_ids(ns));
701
                up_read(&shm_ids(ns).rw_mutex);
702
                if(copy_to_user (buf, &shm_info, sizeof(shm_info))) {
703
                        err = -EFAULT;
704
                        goto out;
705
                }
706
 
707
                err = err < 0 ? 0 : err;
708
                goto out;
709
        }
710
        case SHM_STAT:
711
        case IPC_STAT:
712
        {
713
                struct shmid64_ds tbuf;
714
                int result;
715
 
716
                if (!buf) {
717
                        err = -EFAULT;
718
                        goto out;
719
                }
720
 
721
                if (cmd == SHM_STAT) {
722
                        shp = shm_lock(ns, shmid);
723
                        if (IS_ERR(shp)) {
724
                                err = PTR_ERR(shp);
725
                                goto out;
726
                        }
727
                        result = shp->shm_perm.id;
728
                } else {
729
                        shp = shm_lock_check(ns, shmid);
730
                        if (IS_ERR(shp)) {
731
                                err = PTR_ERR(shp);
732
                                goto out;
733
                        }
734
                        result = 0;
735
                }
736
                err=-EACCES;
737
                if (ipcperms (&shp->shm_perm, S_IRUGO))
738
                        goto out_unlock;
739
                err = security_shm_shmctl(shp, cmd);
740
                if (err)
741
                        goto out_unlock;
742
                memset(&tbuf, 0, sizeof(tbuf));
743
                kernel_to_ipc64_perm(&shp->shm_perm, &tbuf.shm_perm);
744
                tbuf.shm_segsz  = shp->shm_segsz;
745
                tbuf.shm_atime  = shp->shm_atim;
746
                tbuf.shm_dtime  = shp->shm_dtim;
747
                tbuf.shm_ctime  = shp->shm_ctim;
748
                tbuf.shm_cpid   = shp->shm_cprid;
749
                tbuf.shm_lpid   = shp->shm_lprid;
750
                tbuf.shm_nattch = shp->shm_nattch;
751
                shm_unlock(shp);
752
                if(copy_shmid_to_user (buf, &tbuf, version))
753
                        err = -EFAULT;
754
                else
755
                        err = result;
756
                goto out;
757
        }
758
        case SHM_LOCK:
759
        case SHM_UNLOCK:
760
        {
761
                shp = shm_lock_check(ns, shmid);
762
                if (IS_ERR(shp)) {
763
                        err = PTR_ERR(shp);
764
                        goto out;
765
                }
766
 
767
                err = audit_ipc_obj(&(shp->shm_perm));
768
                if (err)
769
                        goto out_unlock;
770
 
771
                if (!capable(CAP_IPC_LOCK)) {
772
                        err = -EPERM;
773
                        if (current->euid != shp->shm_perm.uid &&
774
                            current->euid != shp->shm_perm.cuid)
775
                                goto out_unlock;
776
                        if (cmd == SHM_LOCK &&
777
                            !current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur)
778
                                goto out_unlock;
779
                }
780
 
781
                err = security_shm_shmctl(shp, cmd);
782
                if (err)
783
                        goto out_unlock;
784
 
785
                if(cmd==SHM_LOCK) {
786
                        struct user_struct * user = current->user;
787
                        if (!is_file_hugepages(shp->shm_file)) {
788
                                err = shmem_lock(shp->shm_file, 1, user);
789
                                if (!err && !(shp->shm_perm.mode & SHM_LOCKED)){
790
                                        shp->shm_perm.mode |= SHM_LOCKED;
791
                                        shp->mlock_user = user;
792
                                }
793
                        }
794
                } else if (!is_file_hugepages(shp->shm_file)) {
795
                        shmem_lock(shp->shm_file, 0, shp->mlock_user);
796
                        shp->shm_perm.mode &= ~SHM_LOCKED;
797
                        shp->mlock_user = NULL;
798
                }
799
                shm_unlock(shp);
800
                goto out;
801
        }
802
        case IPC_RMID:
803
        {
804
                /*
805
                 *      We cannot simply remove the file. The SVID states
806
                 *      that the block remains until the last person
807
                 *      detaches from it, then is deleted. A shmat() on
808
                 *      an RMID segment is legal in older Linux and if
809
                 *      we change it apps break...
810
                 *
811
                 *      Instead we set a destroyed flag, and then blow
812
                 *      the name away when the usage hits zero.
813
                 */
814
                down_write(&shm_ids(ns).rw_mutex);
815
                shp = shm_lock_check_down(ns, shmid);
816
                if (IS_ERR(shp)) {
817
                        err = PTR_ERR(shp);
818
                        goto out_up;
819
                }
820
 
821
                err = audit_ipc_obj(&(shp->shm_perm));
822
                if (err)
823
                        goto out_unlock_up;
824
 
825
                if (current->euid != shp->shm_perm.uid &&
826
                    current->euid != shp->shm_perm.cuid &&
827
                    !capable(CAP_SYS_ADMIN)) {
828
                        err=-EPERM;
829
                        goto out_unlock_up;
830
                }
831
 
832
                err = security_shm_shmctl(shp, cmd);
833
                if (err)
834
                        goto out_unlock_up;
835
 
836
                do_shm_rmid(ns, shp);
837
                up_write(&shm_ids(ns).rw_mutex);
838
                goto out;
839
        }
840
 
841
        case IPC_SET:
842
        {
843
                if (!buf) {
844
                        err = -EFAULT;
845
                        goto out;
846
                }
847
 
848
                if (copy_shmid_from_user (&setbuf, buf, version)) {
849
                        err = -EFAULT;
850
                        goto out;
851
                }
852
                down_write(&shm_ids(ns).rw_mutex);
853
                shp = shm_lock_check_down(ns, shmid);
854
                if (IS_ERR(shp)) {
855
                        err = PTR_ERR(shp);
856
                        goto out_up;
857
                }
858
                err = audit_ipc_obj(&(shp->shm_perm));
859
                if (err)
860
                        goto out_unlock_up;
861
                err = audit_ipc_set_perm(0, setbuf.uid, setbuf.gid, setbuf.mode);
862
                if (err)
863
                        goto out_unlock_up;
864
                err=-EPERM;
865
                if (current->euid != shp->shm_perm.uid &&
866
                    current->euid != shp->shm_perm.cuid &&
867
                    !capable(CAP_SYS_ADMIN)) {
868
                        goto out_unlock_up;
869
                }
870
 
871
                err = security_shm_shmctl(shp, cmd);
872
                if (err)
873
                        goto out_unlock_up;
874
 
875
                shp->shm_perm.uid = setbuf.uid;
876
                shp->shm_perm.gid = setbuf.gid;
877
                shp->shm_perm.mode = (shp->shm_perm.mode & ~S_IRWXUGO)
878
                        | (setbuf.mode & S_IRWXUGO);
879
                shp->shm_ctim = get_seconds();
880
                break;
881
        }
882
 
883
        default:
884
                err = -EINVAL;
885
                goto out;
886
        }
887
 
888
        err = 0;
889
out_unlock_up:
890
        shm_unlock(shp);
891
out_up:
892
        up_write(&shm_ids(ns).rw_mutex);
893
        goto out;
894
out_unlock:
895
        shm_unlock(shp);
896
out:
897
        return err;
898
}
899
 
900
/*
901
 * Fix shmaddr, allocate descriptor, map shm, add attach descriptor to lists.
902
 *
903
 * NOTE! Despite the name, this is NOT a direct system call entrypoint. The
904
 * "raddr" thing points to kernel space, and there has to be a wrapper around
905
 * this.
906
 */
907
long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr)
908
{
909
        struct shmid_kernel *shp;
910
        unsigned long addr;
911
        unsigned long size;
912
        struct file * file;
913
        int    err;
914
        unsigned long flags;
915
        unsigned long prot;
916
        int acc_mode;
917
        unsigned long user_addr;
918
        struct ipc_namespace *ns;
919
        struct shm_file_data *sfd;
920
        struct path path;
921
        mode_t f_mode;
922
 
923
        err = -EINVAL;
924
        if (shmid < 0)
925
                goto out;
926
        else if ((addr = (ulong)shmaddr)) {
927
                if (addr & (SHMLBA-1)) {
928
                        if (shmflg & SHM_RND)
929
                                addr &= ~(SHMLBA-1);       /* round down */
930
                        else
931
#ifndef __ARCH_FORCE_SHMLBA
932
                                if (addr & ~PAGE_MASK)
933
#endif
934
                                        goto out;
935
                }
936
                flags = MAP_SHARED | MAP_FIXED;
937
        } else {
938
                if ((shmflg & SHM_REMAP))
939
                        goto out;
940
 
941
                flags = MAP_SHARED;
942
        }
943
 
944
        if (shmflg & SHM_RDONLY) {
945
                prot = PROT_READ;
946
                acc_mode = S_IRUGO;
947
                f_mode = FMODE_READ;
948
        } else {
949
                prot = PROT_READ | PROT_WRITE;
950
                acc_mode = S_IRUGO | S_IWUGO;
951
                f_mode = FMODE_READ | FMODE_WRITE;
952
        }
953
        if (shmflg & SHM_EXEC) {
954
                prot |= PROT_EXEC;
955
                acc_mode |= S_IXUGO;
956
        }
957
 
958
        /*
959
         * We cannot rely on the fs check since SYSV IPC does have an
960
         * additional creator id...
961
         */
962
        ns = current->nsproxy->ipc_ns;
963
        shp = shm_lock_check(ns, shmid);
964
        if (IS_ERR(shp)) {
965
                err = PTR_ERR(shp);
966
                goto out;
967
        }
968
 
969
        err = -EACCES;
970
        if (ipcperms(&shp->shm_perm, acc_mode))
971
                goto out_unlock;
972
 
973
        err = security_shm_shmat(shp, shmaddr, shmflg);
974
        if (err)
975
                goto out_unlock;
976
 
977
        path.dentry = dget(shp->shm_file->f_path.dentry);
978
        path.mnt    = shp->shm_file->f_path.mnt;
979
        shp->shm_nattch++;
980
        size = i_size_read(path.dentry->d_inode);
981
        shm_unlock(shp);
982
 
983
        err = -ENOMEM;
984
        sfd = kzalloc(sizeof(*sfd), GFP_KERNEL);
985
        if (!sfd)
986
                goto out_put_dentry;
987
 
988
        err = -ENOMEM;
989
 
990
        file = alloc_file(path.mnt, path.dentry, f_mode, &shm_file_operations);
991
        if (!file)
992
                goto out_free;
993
 
994
        file->private_data = sfd;
995
        file->f_mapping = shp->shm_file->f_mapping;
996
        sfd->id = shp->shm_perm.id;
997
        sfd->ns = get_ipc_ns(ns);
998
        sfd->file = shp->shm_file;
999
        sfd->vm_ops = NULL;
1000
 
1001
        down_write(&current->mm->mmap_sem);
1002
        if (addr && !(shmflg & SHM_REMAP)) {
1003
                err = -EINVAL;
1004
                if (find_vma_intersection(current->mm, addr, addr + size))
1005
                        goto invalid;
1006
                /*
1007
                 * If shm segment goes below stack, make sure there is some
1008
                 * space left for the stack to grow (at least 4 pages).
1009
                 */
1010
                if (addr < current->mm->start_stack &&
1011
                    addr > current->mm->start_stack - size - PAGE_SIZE * 5)
1012
                        goto invalid;
1013
        }
1014
 
1015
        user_addr = do_mmap (file, addr, size, prot, flags, 0);
1016
        *raddr = user_addr;
1017
        err = 0;
1018
        if (IS_ERR_VALUE(user_addr))
1019
                err = (long)user_addr;
1020
invalid:
1021
        up_write(&current->mm->mmap_sem);
1022
 
1023
        fput(file);
1024
 
1025
out_nattch:
1026
        down_write(&shm_ids(ns).rw_mutex);
1027
        shp = shm_lock_down(ns, shmid);
1028
        BUG_ON(IS_ERR(shp));
1029
        shp->shm_nattch--;
1030
        if(shp->shm_nattch == 0 &&
1031
           shp->shm_perm.mode & SHM_DEST)
1032
                shm_destroy(ns, shp);
1033
        else
1034
                shm_unlock(shp);
1035
        up_write(&shm_ids(ns).rw_mutex);
1036
 
1037
out:
1038
        return err;
1039
 
1040
out_unlock:
1041
        shm_unlock(shp);
1042
        goto out;
1043
 
1044
out_free:
1045
        kfree(sfd);
1046
out_put_dentry:
1047
        dput(path.dentry);
1048
        goto out_nattch;
1049
}
1050
 
1051
asmlinkage long sys_shmat(int shmid, char __user *shmaddr, int shmflg)
1052
{
1053
        unsigned long ret;
1054
        long err;
1055
 
1056
        err = do_shmat(shmid, shmaddr, shmflg, &ret);
1057
        if (err)
1058
                return err;
1059
        force_successful_syscall_return();
1060
        return (long)ret;
1061
}
1062
 
1063
/*
1064
 * detach and kill segment if marked destroyed.
1065
 * The work is done in shm_close.
1066
 */
1067
asmlinkage long sys_shmdt(char __user *shmaddr)
1068
{
1069
        struct mm_struct *mm = current->mm;
1070
        struct vm_area_struct *vma, *next;
1071
        unsigned long addr = (unsigned long)shmaddr;
1072
        loff_t size = 0;
1073
        int retval = -EINVAL;
1074
 
1075
        if (addr & ~PAGE_MASK)
1076
                return retval;
1077
 
1078
        down_write(&mm->mmap_sem);
1079
 
1080
        /*
1081
         * This function tries to be smart and unmap shm segments that
1082
         * were modified by partial mlock or munmap calls:
1083
         * - It first determines the size of the shm segment that should be
1084
         *   unmapped: It searches for a vma that is backed by shm and that
1085
         *   started at address shmaddr. It records it's size and then unmaps
1086
         *   it.
1087
         * - Then it unmaps all shm vmas that started at shmaddr and that
1088
         *   are within the initially determined size.
1089
         * Errors from do_munmap are ignored: the function only fails if
1090
         * it's called with invalid parameters or if it's called to unmap
1091
         * a part of a vma. Both calls in this function are for full vmas,
1092
         * the parameters are directly copied from the vma itself and always
1093
         * valid - therefore do_munmap cannot fail. (famous last words?)
1094
         */
1095
        /*
1096
         * If it had been mremap()'d, the starting address would not
1097
         * match the usual checks anyway. So assume all vma's are
1098
         * above the starting address given.
1099
         */
1100
        vma = find_vma(mm, addr);
1101
 
1102
        while (vma) {
1103
                next = vma->vm_next;
1104
 
1105
                /*
1106
                 * Check if the starting address would match, i.e. it's
1107
                 * a fragment created by mprotect() and/or munmap(), or it
1108
                 * otherwise it starts at this address with no hassles.
1109
                 */
1110
                if ((vma->vm_ops == &shm_vm_ops) &&
1111
                        (vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff) {
1112
 
1113
 
1114
                        size = vma->vm_file->f_path.dentry->d_inode->i_size;
1115
                        do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start);
1116
                        /*
1117
                         * We discovered the size of the shm segment, so
1118
                         * break out of here and fall through to the next
1119
                         * loop that uses the size information to stop
1120
                         * searching for matching vma's.
1121
                         */
1122
                        retval = 0;
1123
                        vma = next;
1124
                        break;
1125
                }
1126
                vma = next;
1127
        }
1128
 
1129
        /*
1130
         * We need look no further than the maximum address a fragment
1131
         * could possibly have landed at. Also cast things to loff_t to
1132
         * prevent overflows and make comparisions vs. equal-width types.
1133
         */
1134
        size = PAGE_ALIGN(size);
1135
        while (vma && (loff_t)(vma->vm_end - addr) <= size) {
1136
                next = vma->vm_next;
1137
 
1138
                /* finding a matching vma now does not alter retval */
1139
                if ((vma->vm_ops == &shm_vm_ops) &&
1140
                        (vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff)
1141
 
1142
                        do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start);
1143
                vma = next;
1144
        }
1145
 
1146
        up_write(&mm->mmap_sem);
1147
        return retval;
1148
}
1149
 
1150
#ifdef CONFIG_PROC_FS
1151
static int sysvipc_shm_proc_show(struct seq_file *s, void *it)
1152
{
1153
        struct shmid_kernel *shp = it;
1154
        char *format;
1155
 
1156
#define SMALL_STRING "%10d %10d  %4o %10u %5u %5u  %5d %5u %5u %5u %5u %10lu %10lu %10lu\n"
1157
#define BIG_STRING   "%10d %10d  %4o %21u %5u %5u  %5d %5u %5u %5u %5u %10lu %10lu %10lu\n"
1158
 
1159
        if (sizeof(size_t) <= sizeof(int))
1160
                format = SMALL_STRING;
1161
        else
1162
                format = BIG_STRING;
1163
        return seq_printf(s, format,
1164
                          shp->shm_perm.key,
1165
                          shp->shm_perm.id,
1166
                          shp->shm_perm.mode,
1167
                          shp->shm_segsz,
1168
                          shp->shm_cprid,
1169
                          shp->shm_lprid,
1170
                          shp->shm_nattch,
1171
                          shp->shm_perm.uid,
1172
                          shp->shm_perm.gid,
1173
                          shp->shm_perm.cuid,
1174
                          shp->shm_perm.cgid,
1175
                          shp->shm_atim,
1176
                          shp->shm_dtim,
1177
                          shp->shm_ctim);
1178
}
1179
#endif

powered by: WebSVN 2.1.0

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