The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/sysv_shm.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /* $FreeBSD$ */
    2 /*      $NetBSD: sysv_shm.c,v 1.23 1994/07/04 23:25:12 glass Exp $      */
    3 
    4 /*
    5  * Copyright (c) 1994 Adam Glass and Charles Hannum.  All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. All advertising materials mentioning features or use of this software
   16  *    must display the following acknowledgement:
   17  *      This product includes software developed by Adam Glass and Charles
   18  *      Hannum.
   19  * 4. The names of the authors may not be used to endorse or promote products
   20  *    derived from this software without specific prior written permission.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
   23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   25  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   32  */
   33 
   34 #include "opt_compat.h"
   35 #include "opt_sysvipc.h"
   36 
   37 #include <sys/param.h>
   38 #include <sys/systm.h>
   39 #include <sys/sysproto.h>
   40 #include <sys/kernel.h>
   41 #include <sys/sysctl.h>
   42 #include <sys/shm.h>
   43 #include <sys/proc.h>
   44 #include <sys/malloc.h>
   45 #include <sys/mman.h>
   46 #include <sys/stat.h>
   47 #include <sys/sysent.h>
   48 #include <sys/jail.h>
   49 
   50 #include <vm/vm.h>
   51 #include <vm/vm_param.h>
   52 #include <sys/lock.h>
   53 #include <vm/pmap.h>
   54 #include <vm/vm_object.h>
   55 #include <vm/vm_map.h>
   56 #include <vm/vm_page.h>
   57 #include <vm/vm_pager.h>
   58 
   59 static MALLOC_DEFINE(M_SHM, "shm", "SVID compatible shared memory segments");
   60 
   61 struct oshmctl_args;
   62 static int oshmctl __P((struct proc *p, struct oshmctl_args *uap));
   63 
   64 static int shmget_allocate_segment __P((struct proc *p, struct shmget_args *uap, int mode));
   65 static int shmget_existing __P((struct proc *p, struct shmget_args *uap, int mode, int segnum));
   66 
   67 /* XXX casting to (sy_call_t *) is bogus, as usual. */
   68 static sy_call_t *shmcalls[] = {
   69         (sy_call_t *)shmat, (sy_call_t *)oshmctl,
   70         (sy_call_t *)shmdt, (sy_call_t *)shmget,
   71         (sy_call_t *)shmctl
   72 };
   73 
   74 #define SHMSEG_FREE             0x0200
   75 #define SHMSEG_REMOVED          0x0400
   76 #define SHMSEG_ALLOCATED        0x0800
   77 #define SHMSEG_WANTED           0x1000
   78 
   79 static int shm_last_free, shm_nused, shm_committed, shmalloced;
   80 static struct shmid_ds  *shmsegs;
   81 
   82 struct shm_handle {
   83         /* vm_offset_t kva; */
   84         vm_object_t shm_object;
   85 };
   86 
   87 struct shmmap_state {
   88         vm_offset_t va;
   89         int shmid;
   90 };
   91 
   92 static void shm_deallocate_segment __P((struct shmid_ds *));
   93 static int shm_find_segment_by_key __P((key_t));
   94 static struct shmid_ds *shm_find_segment_by_shmid __P((int));
   95 static int shm_delete_mapping __P((struct proc *, struct shmmap_state *));
   96 static void shmrealloc __P((void));
   97 static void shminit __P((void *));
   98 
   99 /*
  100  * Tuneable values
  101  */
  102 #ifndef SHMMAXPGS
  103 #define SHMMAXPGS       8192    /* note: sysv shared memory is swap backed */
  104 #endif
  105 #ifndef SHMMAX
  106 #define SHMMAX  (SHMMAXPGS*PAGE_SIZE)
  107 #endif
  108 #ifndef SHMMIN
  109 #define SHMMIN  1
  110 #endif
  111 #ifndef SHMMNI
  112 #define SHMMNI  192
  113 #endif
  114 #ifndef SHMSEG
  115 #define SHMSEG  128
  116 #endif
  117 #ifndef SHMALL
  118 #define SHMALL  (SHMMAXPGS)
  119 #endif
  120 
  121 struct  shminfo shminfo = {
  122         SHMMAX,
  123         SHMMIN,
  124         SHMMNI,
  125         SHMSEG,
  126         SHMALL
  127 };
  128 
  129 static int shm_use_phys;
  130 static int shm_allow_removed;
  131 
  132 TUNABLE_INT("kern.ipc.shmmin", &shminfo.shmmin);
  133 TUNABLE_INT("kern.ipc.shmmni", &shminfo.shmmni);
  134 TUNABLE_INT("kern.ipc.shmseg", &shminfo.shmseg);
  135 TUNABLE_INT("kern.ipc.shmmaxpgs", &shminfo.shmall);
  136 TUNABLE_INT("kern.ipc.shm_use_phys", &shm_use_phys);
  137 
  138 SYSCTL_DECL(_kern_ipc);
  139 SYSCTL_INT(_kern_ipc, OID_AUTO, shmmax, CTLFLAG_RW, &shminfo.shmmax, 0, "");
  140 SYSCTL_INT(_kern_ipc, OID_AUTO, shmmin, CTLFLAG_RW, &shminfo.shmmin, 0, "");
  141 SYSCTL_INT(_kern_ipc, OID_AUTO, shmmni, CTLFLAG_RD, &shminfo.shmmni, 0, "");
  142 SYSCTL_INT(_kern_ipc, OID_AUTO, shmseg, CTLFLAG_RW, &shminfo.shmseg, 0, "");
  143 SYSCTL_INT(_kern_ipc, OID_AUTO, shmall, CTLFLAG_RW, &shminfo.shmall, 0, "");
  144 SYSCTL_INT(_kern_ipc, OID_AUTO, shm_use_phys, CTLFLAG_RW, &shm_use_phys, 0, "");
  145 SYSCTL_INT(_kern_ipc, OID_AUTO, shm_allow_removed, CTLFLAG_RW, &shm_allow_removed, 0, "");
  146 
  147 static int
  148 shm_find_segment_by_key(key)
  149         key_t key;
  150 {
  151         int i;
  152 
  153         for (i = 0; i < shmalloced; i++)
  154                 if ((shmsegs[i].shm_perm.mode & SHMSEG_ALLOCATED) &&
  155                     shmsegs[i].shm_perm.key == key)
  156                         return i;
  157         return -1;
  158 }
  159 
  160 static struct shmid_ds *
  161 shm_find_segment_by_shmid(shmid)
  162         int shmid;
  163 {
  164         int segnum;
  165         struct shmid_ds *shmseg;
  166 
  167         segnum = IPCID_TO_IX(shmid);
  168         if (segnum < 0 || segnum >= shmalloced)
  169                 return NULL;
  170         shmseg = &shmsegs[segnum];
  171         if ((shmseg->shm_perm.mode & SHMSEG_ALLOCATED) == 0 ||
  172             (!shm_allow_removed &&
  173              (shmseg->shm_perm.mode & SHMSEG_REMOVED) != 0) ||
  174             shmseg->shm_perm.seq != IPCID_TO_SEQ(shmid))
  175                 return NULL;
  176         return shmseg;
  177 }
  178 
  179 static void
  180 shm_deallocate_segment(shmseg)
  181         struct shmid_ds *shmseg;
  182 {
  183         struct shm_handle *shm_handle;
  184         size_t size;
  185 
  186         shm_handle = shmseg->shm_internal;
  187         vm_object_deallocate(shm_handle->shm_object);
  188         free((caddr_t)shm_handle, M_SHM);
  189         shmseg->shm_internal = NULL;
  190         size = round_page(shmseg->shm_segsz);
  191         shm_committed -= btoc(size);
  192         shm_nused--;
  193         shmseg->shm_perm.mode = SHMSEG_FREE;
  194 }
  195 
  196 static int
  197 shm_delete_mapping(p, shmmap_s)
  198         struct proc *p;
  199         struct shmmap_state *shmmap_s;
  200 {
  201         struct shmid_ds *shmseg;
  202         int segnum, result;
  203         size_t size;
  204 
  205         segnum = IPCID_TO_IX(shmmap_s->shmid);
  206         shmseg = &shmsegs[segnum];
  207         size = round_page(shmseg->shm_segsz);
  208         result = vm_map_remove(&p->p_vmspace->vm_map, shmmap_s->va, shmmap_s->va + size);
  209         if (result != KERN_SUCCESS)
  210                 return EINVAL;
  211         shmmap_s->shmid = -1;
  212         shmseg->shm_dtime = time_second;
  213         if ((--shmseg->shm_nattch <= 0) &&
  214             (shmseg->shm_perm.mode & SHMSEG_REMOVED)) {
  215                 shm_deallocate_segment(shmseg);
  216                 shm_last_free = segnum;
  217         }
  218         return 0;
  219 }
  220 
  221 #ifndef _SYS_SYSPROTO_H_
  222 struct shmdt_args {
  223         void *shmaddr;
  224 };
  225 #endif
  226 
  227 int
  228 shmdt(p, uap)
  229         struct proc *p;
  230         struct shmdt_args *uap;
  231 {
  232         struct shmmap_state *shmmap_s;
  233         int i;
  234 
  235         if (!jail_sysvipc_allowed && p->p_prison != NULL)
  236                 return (ENOSYS);
  237 
  238         shmmap_s = (struct shmmap_state *)p->p_vmspace->vm_shm;
  239         if (shmmap_s == NULL)
  240             return EINVAL;
  241         for (i = 0; i < shminfo.shmseg; i++, shmmap_s++)
  242                 if (shmmap_s->shmid != -1 &&
  243                     shmmap_s->va == (vm_offset_t)uap->shmaddr)
  244                         break;
  245         if (i == shminfo.shmseg)
  246                 return EINVAL;
  247         return shm_delete_mapping(p, shmmap_s);
  248 }
  249 
  250 #ifndef _SYS_SYSPROTO_H_
  251 struct shmat_args {
  252         int shmid;
  253         void *shmaddr;
  254         int shmflg;
  255 };
  256 #endif
  257 
  258 int
  259 shmat(p, uap)
  260         struct proc *p;
  261         struct shmat_args *uap;
  262 {
  263         int error, i, flags;
  264         struct shmid_ds *shmseg;
  265         struct shmmap_state *shmmap_s = NULL;
  266         struct shm_handle *shm_handle;
  267         vm_offset_t attach_va;
  268         vm_prot_t prot;
  269         vm_size_t size;
  270         int rv;
  271 
  272         if (!jail_sysvipc_allowed && p->p_prison != NULL)
  273                 return (ENOSYS);
  274 
  275         shmmap_s = (struct shmmap_state *)p->p_vmspace->vm_shm;
  276         if (shmmap_s == NULL) {
  277                 size = shminfo.shmseg * sizeof(struct shmmap_state);
  278                 shmmap_s = malloc(size, M_SHM, M_WAITOK);
  279                 for (i = 0; i < shminfo.shmseg; i++)
  280                         shmmap_s[i].shmid = -1;
  281                 p->p_vmspace->vm_shm = (caddr_t)shmmap_s;
  282         }
  283         shmseg = shm_find_segment_by_shmid(uap->shmid);
  284         if (shmseg == NULL)
  285                 return EINVAL;
  286         error = ipcperm(p, &shmseg->shm_perm,
  287             (uap->shmflg & SHM_RDONLY) ? IPC_R : IPC_R|IPC_W);
  288         if (error)
  289                 return error;
  290         for (i = 0; i < shminfo.shmseg; i++) {
  291                 if (shmmap_s->shmid == -1)
  292                         break;
  293                 shmmap_s++;
  294         }
  295         if (i >= shminfo.shmseg)
  296                 return EMFILE;
  297         size = round_page(shmseg->shm_segsz);
  298 #ifdef VM_PROT_READ_IS_EXEC
  299         prot = VM_PROT_READ | VM_PROT_EXECUTE;
  300 #else
  301         prot = VM_PROT_READ;
  302 #endif
  303         if ((uap->shmflg & SHM_RDONLY) == 0)
  304                 prot |= VM_PROT_WRITE;
  305         flags = MAP_ANON | MAP_SHARED;
  306         if (uap->shmaddr) {
  307                 flags |= MAP_FIXED;
  308                 if (uap->shmflg & SHM_RND)
  309                         attach_va = (vm_offset_t)uap->shmaddr & ~(SHMLBA-1);
  310                 else if (((vm_offset_t)uap->shmaddr & (SHMLBA-1)) == 0)
  311                         attach_va = (vm_offset_t)uap->shmaddr;
  312                 else
  313                         return EINVAL;
  314         } else {
  315                 /* This is just a hint to vm_map_find() about where to put it. */
  316                 attach_va = round_page((vm_offset_t)p->p_vmspace->vm_taddr + maxtsiz + maxdsiz);
  317         }
  318 
  319         shm_handle = shmseg->shm_internal;
  320         vm_object_reference(shm_handle->shm_object);
  321         rv = vm_map_find(&p->p_vmspace->vm_map, shm_handle->shm_object,
  322                 0, &attach_va, size, (flags & MAP_FIXED)?0:1, prot, prot, 0);
  323         if (rv != KERN_SUCCESS) {
  324                 vm_object_deallocate(shm_handle->shm_object);
  325                 return ENOMEM;
  326         }
  327         vm_map_inherit(&p->p_vmspace->vm_map,
  328                 attach_va, attach_va + size, VM_INHERIT_SHARE);
  329 
  330         shmmap_s->va = attach_va;
  331         shmmap_s->shmid = uap->shmid;
  332         shmseg->shm_lpid = p->p_pid;
  333         shmseg->shm_atime = time_second;
  334         shmseg->shm_nattch++;
  335         p->p_retval[0] = attach_va;
  336         return 0;
  337 }
  338 
  339 struct oshmid_ds {
  340         struct  ipc_perm shm_perm;      /* operation perms */
  341         int     shm_segsz;              /* size of segment (bytes) */
  342         ushort  shm_cpid;               /* pid, creator */
  343         ushort  shm_lpid;               /* pid, last operation */
  344         short   shm_nattch;             /* no. of current attaches */
  345         time_t  shm_atime;              /* last attach time */
  346         time_t  shm_dtime;              /* last detach time */
  347         time_t  shm_ctime;              /* last change time */
  348         void    *shm_handle;            /* internal handle for shm segment */
  349 };
  350 
  351 struct oshmctl_args {
  352         int shmid;
  353         int cmd;
  354         struct oshmid_ds *ubuf;
  355 };
  356 
  357 static int
  358 oshmctl(p, uap)
  359         struct proc *p;
  360         struct oshmctl_args *uap;
  361 {
  362 #ifdef COMPAT_43
  363         int error;
  364         struct shmid_ds *shmseg;
  365         struct oshmid_ds outbuf;
  366 
  367         if (!jail_sysvipc_allowed && p->p_prison != NULL)
  368                 return (ENOSYS);
  369 
  370         shmseg = shm_find_segment_by_shmid(uap->shmid);
  371         if (shmseg == NULL)
  372                 return EINVAL;
  373         switch (uap->cmd) {
  374         case IPC_STAT:
  375                 error = ipcperm(p, &shmseg->shm_perm, IPC_R);
  376                 if (error)
  377                         return error;
  378                 outbuf.shm_perm = shmseg->shm_perm;
  379                 outbuf.shm_segsz = shmseg->shm_segsz;
  380                 outbuf.shm_cpid = shmseg->shm_cpid;
  381                 outbuf.shm_lpid = shmseg->shm_lpid;
  382                 outbuf.shm_nattch = shmseg->shm_nattch;
  383                 outbuf.shm_atime = shmseg->shm_atime;
  384                 outbuf.shm_dtime = shmseg->shm_dtime;
  385                 outbuf.shm_ctime = shmseg->shm_ctime;
  386                 outbuf.shm_handle = shmseg->shm_internal;
  387                 error = copyout((caddr_t)&outbuf, uap->ubuf, sizeof(outbuf));
  388                 if (error)
  389                         return error;
  390                 break;
  391         default:
  392                 /* XXX casting to (sy_call_t *) is bogus, as usual. */
  393                 return ((sy_call_t *)shmctl)(p, uap);
  394         }
  395         return 0;
  396 #else
  397         return EINVAL;
  398 #endif
  399 }
  400 
  401 #ifndef _SYS_SYSPROTO_H_
  402 struct shmctl_args {
  403         int shmid;
  404         int cmd;
  405         struct shmid_ds *buf;
  406 };
  407 #endif
  408 
  409 int
  410 shmctl(p, uap)
  411         struct proc *p;
  412         struct shmctl_args *uap;
  413 {
  414         int error;
  415         struct shmid_ds inbuf;
  416         struct shmid_ds *shmseg;
  417 
  418         if (!jail_sysvipc_allowed && p->p_prison != NULL)
  419                 return (ENOSYS);
  420 
  421         shmseg = shm_find_segment_by_shmid(uap->shmid);
  422         if (shmseg == NULL)
  423                 return EINVAL;
  424         switch (uap->cmd) {
  425         case IPC_STAT:
  426                 error = ipcperm(p, &shmseg->shm_perm, IPC_R);
  427                 if (error)
  428                         return error;
  429                 error = copyout((caddr_t)shmseg, uap->buf, sizeof(inbuf));
  430                 if (error)
  431                         return error;
  432                 break;
  433         case IPC_SET:
  434                 error = ipcperm(p, &shmseg->shm_perm, IPC_M);
  435                 if (error)
  436                         return error;
  437                 error = copyin(uap->buf, (caddr_t)&inbuf, sizeof(inbuf));
  438                 if (error)
  439                         return error;
  440                 shmseg->shm_perm.uid = inbuf.shm_perm.uid;
  441                 shmseg->shm_perm.gid = inbuf.shm_perm.gid;
  442                 shmseg->shm_perm.mode =
  443                     (shmseg->shm_perm.mode & ~ACCESSPERMS) |
  444                     (inbuf.shm_perm.mode & ACCESSPERMS);
  445                 shmseg->shm_ctime = time_second;
  446                 break;
  447         case IPC_RMID:
  448                 error = ipcperm(p, &shmseg->shm_perm, IPC_M);
  449                 if (error)
  450                         return error;
  451                 shmseg->shm_perm.key = IPC_PRIVATE;
  452                 shmseg->shm_perm.mode |= SHMSEG_REMOVED;
  453                 if (shmseg->shm_nattch <= 0) {
  454                         shm_deallocate_segment(shmseg);
  455                         shm_last_free = IPCID_TO_IX(uap->shmid);
  456                 }
  457                 break;
  458 #if 0
  459         case SHM_LOCK:
  460         case SHM_UNLOCK:
  461 #endif
  462         default:
  463                 return EINVAL;
  464         }
  465         return 0;
  466 }
  467 
  468 #ifndef _SYS_SYSPROTO_H_
  469 struct shmget_args {
  470         key_t key;
  471         size_t size;
  472         int shmflg;
  473 };
  474 #endif
  475 
  476 static int
  477 shmget_existing(p, uap, mode, segnum)
  478         struct proc *p;
  479         struct shmget_args *uap;
  480         int mode;
  481         int segnum;
  482 {
  483         struct shmid_ds *shmseg;
  484         int error;
  485 
  486         shmseg = &shmsegs[segnum];
  487         if (shmseg->shm_perm.mode & SHMSEG_REMOVED) {
  488                 /*
  489                  * This segment is in the process of being allocated.  Wait
  490                  * until it's done, and look the key up again (in case the
  491                  * allocation failed or it was freed).
  492                  */
  493                 shmseg->shm_perm.mode |= SHMSEG_WANTED;
  494                 error = tsleep((caddr_t)shmseg, PLOCK | PCATCH, "shmget", 0);
  495                 if (error)
  496                         return error;
  497                 return EAGAIN;
  498         }
  499         if ((uap->shmflg & (IPC_CREAT | IPC_EXCL)) == (IPC_CREAT | IPC_EXCL))
  500                 return EEXIST;
  501         error = ipcperm(p, &shmseg->shm_perm, mode);
  502         if (error)
  503                 return error;
  504         if (uap->size && uap->size > shmseg->shm_segsz)
  505                 return EINVAL;
  506         p->p_retval[0] = IXSEQ_TO_IPCID(segnum, shmseg->shm_perm);
  507         return 0;
  508 }
  509 
  510 static int
  511 shmget_allocate_segment(p, uap, mode)
  512         struct proc *p;
  513         struct shmget_args *uap;
  514         int mode;
  515 {
  516         int i, segnum, shmid, size;
  517         struct ucred *cred = p->p_ucred;
  518         struct shmid_ds *shmseg;
  519         struct shm_handle *shm_handle;
  520 
  521         if (uap->size < shminfo.shmmin || uap->size > shminfo.shmmax)
  522                 return EINVAL;
  523         if (shm_nused >= shminfo.shmmni) /* any shmids left? */
  524                 return ENOSPC;
  525         size = round_page(uap->size);
  526         if (shm_committed + btoc(size) > shminfo.shmall)
  527                 return ENOMEM;
  528         if (shm_last_free < 0) {
  529                 shmrealloc();   /* maybe expand the shmsegs[] array */
  530                 for (i = 0; i < shmalloced; i++)
  531                         if (shmsegs[i].shm_perm.mode & SHMSEG_FREE)
  532                                 break;
  533                 if (i == shmalloced)
  534                         return ENOSPC;
  535                 segnum = i;
  536         } else  {
  537                 segnum = shm_last_free;
  538                 shm_last_free = -1;
  539         }
  540         shmseg = &shmsegs[segnum];
  541         /*
  542          * In case we sleep in malloc(), mark the segment present but deleted
  543          * so that noone else tries to create the same key.
  544          */
  545         shmseg->shm_perm.mode = SHMSEG_ALLOCATED | SHMSEG_REMOVED;
  546         shmseg->shm_perm.key = uap->key;
  547         shmseg->shm_perm.seq = (shmseg->shm_perm.seq + 1) & 0x7fff;
  548         shm_handle = (struct shm_handle *)
  549             malloc(sizeof(struct shm_handle), M_SHM, M_WAITOK);
  550         shmid = IXSEQ_TO_IPCID(segnum, shmseg->shm_perm);
  551         
  552         /*
  553          * We make sure that we have allocated a pager before we need
  554          * to.
  555          */
  556         if (shm_use_phys) {
  557                 shm_handle->shm_object =
  558                     vm_pager_allocate(OBJT_PHYS, 0, size, VM_PROT_DEFAULT, 0);
  559         } else {
  560                 shm_handle->shm_object =
  561                     vm_pager_allocate(OBJT_SWAP, 0, size, VM_PROT_DEFAULT, 0);
  562         }
  563         vm_object_clear_flag(shm_handle->shm_object, OBJ_ONEMAPPING);
  564         vm_object_set_flag(shm_handle->shm_object, OBJ_NOSPLIT);
  565 
  566         shmseg->shm_internal = shm_handle;
  567         shmseg->shm_perm.cuid = shmseg->shm_perm.uid = cred->cr_uid;
  568         shmseg->shm_perm.cgid = shmseg->shm_perm.gid = cred->cr_gid;
  569         shmseg->shm_perm.mode = (shmseg->shm_perm.mode & SHMSEG_WANTED) |
  570             (mode & ACCESSPERMS) | SHMSEG_ALLOCATED;
  571         shmseg->shm_segsz = uap->size;
  572         shmseg->shm_cpid = p->p_pid;
  573         shmseg->shm_lpid = shmseg->shm_nattch = 0;
  574         shmseg->shm_atime = shmseg->shm_dtime = 0;
  575         shmseg->shm_ctime = time_second;
  576         shm_committed += btoc(size);
  577         shm_nused++;
  578         if (shmseg->shm_perm.mode & SHMSEG_WANTED) {
  579                 /*
  580                  * Somebody else wanted this key while we were asleep.  Wake
  581                  * them up now.
  582                  */
  583                 shmseg->shm_perm.mode &= ~SHMSEG_WANTED;
  584                 wakeup((caddr_t)shmseg);
  585         }
  586         p->p_retval[0] = shmid;
  587         return 0;
  588 }
  589 
  590 int
  591 shmget(p, uap)
  592         struct proc *p;
  593         struct shmget_args *uap;
  594 {
  595         int segnum, mode, error;
  596 
  597         if (!jail_sysvipc_allowed && p->p_prison != NULL)
  598                 return (ENOSYS);
  599 
  600         mode = uap->shmflg & ACCESSPERMS;
  601         if (uap->key != IPC_PRIVATE) {
  602         again:
  603                 segnum = shm_find_segment_by_key(uap->key);
  604                 if (segnum >= 0) {
  605                         error = shmget_existing(p, uap, mode, segnum);
  606                         if (error == EAGAIN)
  607                                 goto again;
  608                         return error;
  609                 }
  610                 if ((uap->shmflg & IPC_CREAT) == 0)
  611                         return ENOENT;
  612         }
  613         return shmget_allocate_segment(p, uap, mode);
  614 }
  615 
  616 int
  617 shmsys(p, uap)
  618         struct proc *p;
  619         /* XXX actually varargs. */
  620         struct shmsys_args /* {
  621                 u_int   which;
  622                 int     a2;
  623                 int     a3;
  624                 int     a4;
  625         } */ *uap;
  626 {
  627 
  628         if (!jail_sysvipc_allowed && p->p_prison != NULL)
  629                 return (ENOSYS);
  630 
  631         if (uap->which >= sizeof(shmcalls)/sizeof(shmcalls[0]))
  632                 return EINVAL;
  633         return ((*shmcalls[uap->which])(p, &uap->a2));
  634 }
  635 
  636 void
  637 shmfork(p1, p2)
  638         struct proc *p1, *p2;
  639 {
  640         struct shmmap_state *shmmap_s;
  641         size_t size;
  642         int i;
  643 
  644         size = shminfo.shmseg * sizeof(struct shmmap_state);
  645         shmmap_s = malloc(size, M_SHM, M_WAITOK);
  646         bcopy((caddr_t)p1->p_vmspace->vm_shm, (caddr_t)shmmap_s, size);
  647         p2->p_vmspace->vm_shm = (caddr_t)shmmap_s;
  648         for (i = 0; i < shminfo.shmseg; i++, shmmap_s++)
  649                 if (shmmap_s->shmid != -1)
  650                         shmsegs[IPCID_TO_IX(shmmap_s->shmid)].shm_nattch++;
  651 }
  652 
  653 void
  654 shmexit(p)
  655         struct proc *p;
  656 {
  657         struct shmmap_state *shmmap_s;
  658         int i;
  659 
  660         shmmap_s = (struct shmmap_state *)p->p_vmspace->vm_shm;
  661         for (i = 0; i < shminfo.shmseg; i++, shmmap_s++)
  662                 if (shmmap_s->shmid != -1)
  663                         shm_delete_mapping(p, shmmap_s);
  664         free((caddr_t)p->p_vmspace->vm_shm, M_SHM);
  665         p->p_vmspace->vm_shm = NULL;
  666 }
  667 
  668 static void
  669 shmrealloc(void)
  670 {
  671         int i;
  672         struct shmid_ds *newsegs;
  673 
  674         if (shmalloced >= shminfo.shmmni)
  675                 return;
  676 
  677         newsegs = malloc(shminfo.shmmni * sizeof(*newsegs), M_SHM, M_WAITOK);
  678         if (newsegs == NULL)
  679                 return;
  680         for (i = 0; i < shmalloced; i++)
  681                 bcopy(&shmsegs[i], &newsegs[i], sizeof(newsegs[0]));
  682         for (; i < shminfo.shmmni; i++) {
  683                 shmsegs[i].shm_perm.mode = SHMSEG_FREE;
  684                 shmsegs[i].shm_perm.seq = 0;
  685         }
  686         free(shmsegs, M_SHM);
  687         shmsegs = newsegs;
  688         shmalloced = shminfo.shmmni;
  689 }
  690 
  691 static void
  692 shminit(dummy)
  693         void *dummy;
  694 {
  695         int i;
  696 
  697         shminfo.shmmax = shminfo.shmall * PAGE_SIZE;
  698         shmalloced = shminfo.shmmni;
  699         shmsegs = malloc(shmalloced * sizeof(shmsegs[0]), M_SHM, M_WAITOK);
  700         if (shmsegs == NULL)
  701                 panic("cannot allocate initial memory for sysvshm");
  702         for (i = 0; i < shmalloced; i++) {
  703                 shmsegs[i].shm_perm.mode = SHMSEG_FREE;
  704                 shmsegs[i].shm_perm.seq = 0;
  705         }
  706         shm_last_free = 0;
  707         shm_nused = 0;
  708         shm_committed = 0;
  709 }
  710 SYSINIT(sysv_shm, SI_SUB_SYSV_SHM, SI_ORDER_FIRST, shminit, NULL);

Cache object: 2d1b51df6b215c6d0c17ea36bf4493cd


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.