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 /*      $NetBSD: sysv_shm.c,v 1.23 1994/07/04 23:25:12 glass Exp $      */
    2 /*-
    3  * Copyright (c) 1994 Adam Glass and Charles Hannum.  All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 3. All advertising materials mentioning features or use of this software
   14  *    must display the following acknowledgement:
   15  *      This product includes software developed by Adam Glass and Charles
   16  *      Hannum.
   17  * 4. The names of the authors may not be used to endorse or promote products
   18  *    derived from this software without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
   21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   23  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   30  */
   31 /*-
   32  * Copyright (c) 2003-2005 McAfee, Inc.
   33  * All rights reserved.
   34  *
   35  * This software was developed for the FreeBSD Project in part by McAfee
   36  * Research, the Security Research Division of McAfee, Inc under DARPA/SPAWAR
   37  * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS research
   38  * program.
   39  *
   40  * Redistribution and use in source and binary forms, with or without
   41  * modification, are permitted provided that the following conditions
   42  * are met:
   43  * 1. Redistributions of source code must retain the above copyright
   44  *    notice, this list of conditions and the following disclaimer.
   45  * 2. Redistributions in binary form must reproduce the above copyright
   46  *    notice, this list of conditions and the following disclaimer in the
   47  *    documentation and/or other materials provided with the distribution.
   48  *
   49  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   50  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   51  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   52  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   53  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   54  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   55  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   56  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   57  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   58  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   59  * SUCH DAMAGE.
   60  */
   61 
   62 #include <sys/cdefs.h>
   63 __FBSDID("$FreeBSD$");
   64 
   65 #include "opt_compat.h"
   66 #include "opt_sysvipc.h"
   67 #include "opt_mac.h"
   68 
   69 #include <sys/param.h>
   70 #include <sys/systm.h>
   71 #include <sys/kernel.h>
   72 #include <sys/lock.h>
   73 #include <sys/sysctl.h>
   74 #include <sys/shm.h>
   75 #include <sys/proc.h>
   76 #include <sys/malloc.h>
   77 #include <sys/mman.h>
   78 #include <sys/module.h>
   79 #include <sys/mutex.h>
   80 #include <sys/resourcevar.h>
   81 #include <sys/stat.h>
   82 #include <sys/syscall.h>
   83 #include <sys/syscallsubr.h>
   84 #include <sys/sysent.h>
   85 #include <sys/sysproto.h>
   86 #include <sys/jail.h>
   87 
   88 #include <security/mac/mac_framework.h>
   89 
   90 #include <vm/vm.h>
   91 #include <vm/vm_param.h>
   92 #include <vm/pmap.h>
   93 #include <vm/vm_object.h>
   94 #include <vm/vm_map.h>
   95 #include <vm/vm_page.h>
   96 #include <vm/vm_pager.h>
   97 
   98 static MALLOC_DEFINE(M_SHM, "shm", "SVID compatible shared memory segments");
   99 
  100 #if defined(__i386__) && (defined(COMPAT_FREEBSD4) || defined(COMPAT_43))
  101 struct oshmctl_args;
  102 static int oshmctl(struct thread *td, struct oshmctl_args *uap);
  103 #endif
  104 
  105 static int shmget_allocate_segment(struct thread *td,
  106     struct shmget_args *uap, int mode);
  107 static int shmget_existing(struct thread *td, struct shmget_args *uap,
  108     int mode, int segnum);
  109 
  110 #if defined(__i386__) && (defined(COMPAT_FREEBSD4) || defined(COMPAT_43))
  111 /* XXX casting to (sy_call_t *) is bogus, as usual. */
  112 static sy_call_t *shmcalls[] = {
  113         (sy_call_t *)shmat, (sy_call_t *)oshmctl,
  114         (sy_call_t *)shmdt, (sy_call_t *)shmget,
  115         (sy_call_t *)shmctl
  116 };
  117 #endif
  118 
  119 #define SHMSEG_FREE             0x0200
  120 #define SHMSEG_REMOVED          0x0400
  121 #define SHMSEG_ALLOCATED        0x0800
  122 #define SHMSEG_WANTED           0x1000
  123 
  124 static int shm_last_free, shm_nused, shm_committed, shmalloced;
  125 static struct shmid_kernel      *shmsegs;
  126 
  127 struct shmmap_state {
  128         vm_offset_t va;
  129         int shmid;
  130 };
  131 
  132 static void shm_deallocate_segment(struct shmid_kernel *);
  133 static int shm_find_segment_by_key(key_t);
  134 static struct shmid_kernel *shm_find_segment_by_shmid(int);
  135 static struct shmid_kernel *shm_find_segment_by_shmidx(int);
  136 static int shm_delete_mapping(struct vmspace *vm, struct shmmap_state *);
  137 static void shmrealloc(void);
  138 static void shminit(void);
  139 static int sysvshm_modload(struct module *, int, void *);
  140 static int shmunload(void);
  141 static void shmexit_myhook(struct vmspace *vm);
  142 static void shmfork_myhook(struct proc *p1, struct proc *p2);
  143 static int sysctl_shmsegs(SYSCTL_HANDLER_ARGS);
  144 
  145 /*
  146  * Tuneable values.
  147  */
  148 #ifndef SHMMAXPGS
  149 #define SHMMAXPGS       8192    /* Note: sysv shared memory is swap backed. */
  150 #endif
  151 #ifndef SHMMAX
  152 #define SHMMAX  (SHMMAXPGS*PAGE_SIZE)
  153 #endif
  154 #ifndef SHMMIN
  155 #define SHMMIN  1
  156 #endif
  157 #ifndef SHMMNI
  158 #define SHMMNI  192
  159 #endif
  160 #ifndef SHMSEG
  161 #define SHMSEG  128
  162 #endif
  163 #ifndef SHMALL
  164 #define SHMALL  (SHMMAXPGS)
  165 #endif
  166 
  167 struct  shminfo shminfo = {
  168         SHMMAX,
  169         SHMMIN,
  170         SHMMNI,
  171         SHMSEG,
  172         SHMALL
  173 };
  174 
  175 static int shm_use_phys;
  176 static int shm_allow_removed;
  177 
  178 SYSCTL_ULONG(_kern_ipc, OID_AUTO, shmmax, CTLFLAG_RW, &shminfo.shmmax, 0,
  179     "Maximum shared memory segment size");
  180 SYSCTL_ULONG(_kern_ipc, OID_AUTO, shmmin, CTLFLAG_RW, &shminfo.shmmin, 0,
  181     "Minimum shared memory segment size");
  182 SYSCTL_ULONG(_kern_ipc, OID_AUTO, shmmni, CTLFLAG_RDTUN, &shminfo.shmmni, 0,
  183     "Number of shared memory identifiers");
  184 SYSCTL_ULONG(_kern_ipc, OID_AUTO, shmseg, CTLFLAG_RDTUN, &shminfo.shmseg, 0,
  185     "Number of segments per process");
  186 SYSCTL_ULONG(_kern_ipc, OID_AUTO, shmall, CTLFLAG_RW, &shminfo.shmall, 0,
  187     "Maximum number of pages available for shared memory");
  188 SYSCTL_INT(_kern_ipc, OID_AUTO, shm_use_phys, CTLFLAG_RW,
  189     &shm_use_phys, 0, "Enable/Disable locking of shared memory pages in core");
  190 SYSCTL_INT(_kern_ipc, OID_AUTO, shm_allow_removed, CTLFLAG_RW,
  191     &shm_allow_removed, 0,
  192     "Enable/Disable attachment to attached segments marked for removal");
  193 SYSCTL_PROC(_kern_ipc, OID_AUTO, shmsegs, CTLFLAG_RD,
  194     NULL, 0, sysctl_shmsegs, "",
  195     "Current number of shared memory segments allocated");
  196 
  197 static int
  198 shm_find_segment_by_key(key)
  199         key_t key;
  200 {
  201         int i;
  202 
  203         for (i = 0; i < shmalloced; i++)
  204                 if ((shmsegs[i].u.shm_perm.mode & SHMSEG_ALLOCATED) &&
  205                     shmsegs[i].u.shm_perm.key == key)
  206                         return (i);
  207         return (-1);
  208 }
  209 
  210 static struct shmid_kernel *
  211 shm_find_segment_by_shmid(int shmid)
  212 {
  213         int segnum;
  214         struct shmid_kernel *shmseg;
  215 
  216         segnum = IPCID_TO_IX(shmid);
  217         if (segnum < 0 || segnum >= shmalloced)
  218                 return (NULL);
  219         shmseg = &shmsegs[segnum];
  220         if ((shmseg->u.shm_perm.mode & SHMSEG_ALLOCATED) == 0 ||
  221             (!shm_allow_removed &&
  222              (shmseg->u.shm_perm.mode & SHMSEG_REMOVED) != 0) ||
  223             shmseg->u.shm_perm.seq != IPCID_TO_SEQ(shmid))
  224                 return (NULL);
  225         return (shmseg);
  226 }
  227 
  228 static struct shmid_kernel *
  229 shm_find_segment_by_shmidx(int segnum)
  230 {
  231         struct shmid_kernel *shmseg;
  232 
  233         if (segnum < 0 || segnum >= shmalloced)
  234                 return (NULL);
  235         shmseg = &shmsegs[segnum];
  236         if ((shmseg->u.shm_perm.mode & SHMSEG_ALLOCATED) == 0 ||
  237             (!shm_allow_removed &&
  238              (shmseg->u.shm_perm.mode & SHMSEG_REMOVED) != 0))
  239                 return (NULL);
  240         return (shmseg);
  241 }
  242 
  243 static void
  244 shm_deallocate_segment(shmseg)
  245         struct shmid_kernel *shmseg;
  246 {
  247         size_t size;
  248 
  249         GIANT_REQUIRED;
  250 
  251         vm_object_deallocate(shmseg->u.shm_internal);
  252         shmseg->u.shm_internal = NULL;
  253         size = round_page(shmseg->u.shm_segsz);
  254         shm_committed -= btoc(size);
  255         shm_nused--;
  256         shmseg->u.shm_perm.mode = SHMSEG_FREE;
  257 #ifdef MAC
  258         mac_cleanup_sysv_shm(shmseg);
  259 #endif
  260 }
  261 
  262 static int
  263 shm_delete_mapping(struct vmspace *vm, struct shmmap_state *shmmap_s)
  264 {
  265         struct shmid_kernel *shmseg;
  266         int segnum, result;
  267         size_t size;
  268 
  269         GIANT_REQUIRED;
  270 
  271         segnum = IPCID_TO_IX(shmmap_s->shmid);
  272         shmseg = &shmsegs[segnum];
  273         size = round_page(shmseg->u.shm_segsz);
  274         result = vm_map_remove(&vm->vm_map, shmmap_s->va, shmmap_s->va + size);
  275         if (result != KERN_SUCCESS)
  276                 return (EINVAL);
  277         shmmap_s->shmid = -1;
  278         shmseg->u.shm_dtime = time_second;
  279         if ((--shmseg->u.shm_nattch <= 0) &&
  280             (shmseg->u.shm_perm.mode & SHMSEG_REMOVED)) {
  281                 shm_deallocate_segment(shmseg);
  282                 shm_last_free = segnum;
  283         }
  284         return (0);
  285 }
  286 
  287 #ifndef _SYS_SYSPROTO_H_
  288 struct shmdt_args {
  289         const void *shmaddr;
  290 };
  291 #endif
  292 int
  293 shmdt(td, uap)
  294         struct thread *td;
  295         struct shmdt_args *uap;
  296 {
  297         struct proc *p = td->td_proc;
  298         struct shmmap_state *shmmap_s;
  299 #ifdef MAC
  300         struct shmid_kernel *shmsegptr;
  301 #endif
  302         int i;
  303         int error = 0;
  304 
  305         if (!jail_sysvipc_allowed && jailed(td->td_ucred))
  306                 return (ENOSYS);
  307         mtx_lock(&Giant);
  308         shmmap_s = p->p_vmspace->vm_shm;
  309         if (shmmap_s == NULL) {
  310                 error = EINVAL;
  311                 goto done2;
  312         }
  313         for (i = 0; i < shminfo.shmseg; i++, shmmap_s++) {
  314                 if (shmmap_s->shmid != -1 &&
  315                     shmmap_s->va == (vm_offset_t)uap->shmaddr) {
  316                         break;
  317                 }
  318         }
  319         if (i == shminfo.shmseg) {
  320                 error = EINVAL;
  321                 goto done2;
  322         }
  323 #ifdef MAC
  324         shmsegptr = &shmsegs[IPCID_TO_IX(shmmap_s->shmid)];
  325         error = mac_check_sysv_shmdt(td->td_ucred, shmsegptr);
  326         if (error != 0)
  327                 goto done2;
  328 #endif
  329         error = shm_delete_mapping(p->p_vmspace, shmmap_s);
  330 done2:
  331         mtx_unlock(&Giant);
  332         return (error);
  333 }
  334 
  335 #ifndef _SYS_SYSPROTO_H_
  336 struct shmat_args {
  337         int shmid;
  338         const void *shmaddr;
  339         int shmflg;
  340 };
  341 #endif
  342 int
  343 kern_shmat(td, shmid, shmaddr, shmflg)
  344         struct thread *td;
  345         int shmid;
  346         const void *shmaddr;
  347         int shmflg;
  348 {
  349         struct proc *p = td->td_proc;
  350         int i, flags;
  351         struct shmid_kernel *shmseg;
  352         struct shmmap_state *shmmap_s = NULL;
  353         vm_offset_t attach_va;
  354         vm_prot_t prot;
  355         vm_size_t size;
  356         int rv;
  357         int error = 0;
  358 
  359         if (!jail_sysvipc_allowed && jailed(td->td_ucred))
  360                 return (ENOSYS);
  361         mtx_lock(&Giant);
  362         shmmap_s = p->p_vmspace->vm_shm;
  363         if (shmmap_s == NULL) {
  364                 size = shminfo.shmseg * sizeof(struct shmmap_state);
  365                 shmmap_s = malloc(size, M_SHM, M_WAITOK);
  366                 for (i = 0; i < shminfo.shmseg; i++)
  367                         shmmap_s[i].shmid = -1;
  368                 p->p_vmspace->vm_shm = shmmap_s;
  369         }
  370         shmseg = shm_find_segment_by_shmid(shmid);
  371         if (shmseg == NULL) {
  372                 error = EINVAL;
  373                 goto done2;
  374         }
  375         error = ipcperm(td, &shmseg->u.shm_perm,
  376             (shmflg & SHM_RDONLY) ? IPC_R : IPC_R|IPC_W);
  377         if (error)
  378                 goto done2;
  379 #ifdef MAC
  380         error = mac_check_sysv_shmat(td->td_ucred, shmseg, shmflg);
  381         if (error != 0)
  382                 goto done2;
  383 #endif
  384         for (i = 0; i < shminfo.shmseg; i++) {
  385                 if (shmmap_s->shmid == -1)
  386                         break;
  387                 shmmap_s++;
  388         }
  389         if (i >= shminfo.shmseg) {
  390                 error = EMFILE;
  391                 goto done2;
  392         }
  393         size = round_page(shmseg->u.shm_segsz);
  394 #ifdef VM_PROT_READ_IS_EXEC
  395         prot = VM_PROT_READ | VM_PROT_EXECUTE;
  396 #else
  397         prot = VM_PROT_READ;
  398 #endif
  399         if ((shmflg & SHM_RDONLY) == 0)
  400                 prot |= VM_PROT_WRITE;
  401         flags = MAP_ANON | MAP_SHARED;
  402         if (shmaddr) {
  403                 flags |= MAP_FIXED;
  404                 if (shmflg & SHM_RND) {
  405                         attach_va = (vm_offset_t)shmaddr & ~(SHMLBA-1);
  406                 } else if (((vm_offset_t)shmaddr & (SHMLBA-1)) == 0) {
  407                         attach_va = (vm_offset_t)shmaddr;
  408                 } else {
  409                         error = EINVAL;
  410                         goto done2;
  411                 }
  412         } else {
  413                 /*
  414                  * This is just a hint to vm_map_find() about where to
  415                  * put it.
  416                  */
  417                 PROC_LOCK(p);
  418                 attach_va = round_page((vm_offset_t)p->p_vmspace->vm_daddr +
  419                     lim_max(p, RLIMIT_DATA));
  420                 PROC_UNLOCK(p);
  421         }
  422 
  423         vm_object_reference(shmseg->u.shm_internal);
  424         rv = vm_map_find(&p->p_vmspace->vm_map, shmseg->u.shm_internal,
  425                 0, &attach_va, size, (flags & MAP_FIXED)?0:1, prot, prot, 0);
  426         if (rv != KERN_SUCCESS) {
  427                 vm_object_deallocate(shmseg->u.shm_internal);
  428                 error = ENOMEM;
  429                 goto done2;
  430         }
  431         vm_map_inherit(&p->p_vmspace->vm_map,
  432                 attach_va, attach_va + size, VM_INHERIT_SHARE);
  433 
  434         shmmap_s->va = attach_va;
  435         shmmap_s->shmid = shmid;
  436         shmseg->u.shm_lpid = p->p_pid;
  437         shmseg->u.shm_atime = time_second;
  438         shmseg->u.shm_nattch++;
  439         td->td_retval[0] = attach_va;
  440 done2:
  441         mtx_unlock(&Giant);
  442         return (error);
  443 }
  444 
  445 int
  446 shmat(td, uap)
  447         struct thread *td;
  448         struct shmat_args *uap;
  449 {
  450         return kern_shmat(td, uap->shmid, uap->shmaddr, uap->shmflg);
  451 }
  452 
  453 #if defined(__i386__) && (defined(COMPAT_FREEBSD4) || defined(COMPAT_43))
  454 struct oshmid_ds {
  455         struct  ipc_perm shm_perm;      /* operation perms */
  456         int     shm_segsz;              /* size of segment (bytes) */
  457         u_short shm_cpid;               /* pid, creator */
  458         u_short shm_lpid;               /* pid, last operation */
  459         short   shm_nattch;             /* no. of current attaches */
  460         time_t  shm_atime;              /* last attach time */
  461         time_t  shm_dtime;              /* last detach time */
  462         time_t  shm_ctime;              /* last change time */
  463         void    *shm_handle;            /* internal handle for shm segment */
  464 };
  465 
  466 struct oshmctl_args {
  467         int shmid;
  468         int cmd;
  469         struct oshmid_ds *ubuf;
  470 };
  471 static int
  472 oshmctl(td, uap)
  473         struct thread *td;
  474         struct oshmctl_args *uap;
  475 {
  476 #ifdef COMPAT_43
  477         int error = 0;
  478         struct shmid_kernel *shmseg;
  479         struct oshmid_ds outbuf;
  480 
  481         if (!jail_sysvipc_allowed && jailed(td->td_ucred))
  482                 return (ENOSYS);
  483         mtx_lock(&Giant);
  484         shmseg = shm_find_segment_by_shmid(uap->shmid);
  485         if (shmseg == NULL) {
  486                 error = EINVAL;
  487                 goto done2;
  488         }
  489         switch (uap->cmd) {
  490         case IPC_STAT:
  491                 error = ipcperm(td, &shmseg->u.shm_perm, IPC_R);
  492                 if (error)
  493                         goto done2;
  494 #ifdef MAC
  495                 error = mac_check_sysv_shmctl(td->td_ucred, shmseg, uap->cmd);
  496                 if (error != 0)
  497                         goto done2;
  498 #endif
  499                 outbuf.shm_perm = shmseg->u.shm_perm;
  500                 outbuf.shm_segsz = shmseg->u.shm_segsz;
  501                 outbuf.shm_cpid = shmseg->u.shm_cpid;
  502                 outbuf.shm_lpid = shmseg->u.shm_lpid;
  503                 outbuf.shm_nattch = shmseg->u.shm_nattch;
  504                 outbuf.shm_atime = shmseg->u.shm_atime;
  505                 outbuf.shm_dtime = shmseg->u.shm_dtime;
  506                 outbuf.shm_ctime = shmseg->u.shm_ctime;
  507                 outbuf.shm_handle = shmseg->u.shm_internal;
  508                 error = copyout(&outbuf, uap->ubuf, sizeof(outbuf));
  509                 if (error)
  510                         goto done2;
  511                 break;
  512         default:
  513                 error = shmctl(td, (struct shmctl_args *)uap);
  514                 break;
  515         }
  516 done2:
  517         mtx_unlock(&Giant);
  518         return (error);
  519 #else
  520         return (EINVAL);
  521 #endif
  522 }
  523 #endif
  524 
  525 #ifndef _SYS_SYSPROTO_H_
  526 struct shmctl_args {
  527         int shmid;
  528         int cmd;
  529         struct shmid_ds *buf;
  530 };
  531 #endif
  532 int
  533 kern_shmctl(td, shmid, cmd, buf, bufsz)
  534         struct thread *td;
  535         int shmid;
  536         int cmd;
  537         void *buf;
  538         size_t *bufsz;
  539 {
  540         int error = 0;
  541         struct shmid_kernel *shmseg;
  542 
  543         if (!jail_sysvipc_allowed && jailed(td->td_ucred))
  544                 return (ENOSYS);
  545 
  546         mtx_lock(&Giant);
  547         switch (cmd) {
  548         case IPC_INFO:
  549                 memcpy(buf, &shminfo, sizeof(shminfo));
  550                 if (bufsz)
  551                         *bufsz = sizeof(shminfo);
  552                 td->td_retval[0] = shmalloced;
  553                 goto done2;
  554         case SHM_INFO: {
  555                 struct shm_info shm_info;
  556                 shm_info.used_ids = shm_nused;
  557                 shm_info.shm_rss = 0;   /*XXX where to get from ? */
  558                 shm_info.shm_tot = 0;   /*XXX where to get from ? */
  559                 shm_info.shm_swp = 0;   /*XXX where to get from ? */
  560                 shm_info.swap_attempts = 0;     /*XXX where to get from ? */
  561                 shm_info.swap_successes = 0;    /*XXX where to get from ? */
  562                 memcpy(buf, &shm_info, sizeof(shm_info));
  563                 if (bufsz)
  564                         *bufsz = sizeof(shm_info);
  565                 td->td_retval[0] = shmalloced;
  566                 goto done2;
  567         }
  568         }
  569         if (cmd == SHM_STAT)
  570                 shmseg = shm_find_segment_by_shmidx(shmid);
  571         else
  572                 shmseg = shm_find_segment_by_shmid(shmid);
  573         if (shmseg == NULL) {
  574                 error = EINVAL;
  575                 goto done2;
  576         }
  577 #ifdef MAC
  578         error = mac_check_sysv_shmctl(td->td_ucred, shmseg, cmd);
  579         if (error != 0)
  580                 goto done2;
  581 #endif
  582         switch (cmd) {
  583         case SHM_STAT:
  584         case IPC_STAT:
  585                 error = ipcperm(td, &shmseg->u.shm_perm, IPC_R);
  586                 if (error)
  587                         goto done2;
  588                 memcpy(buf, &shmseg->u, sizeof(struct shmid_ds));
  589                 if (bufsz)
  590                         *bufsz = sizeof(struct shmid_ds);
  591                 if (cmd == SHM_STAT)
  592                         td->td_retval[0] = IXSEQ_TO_IPCID(shmid, shmseg->u.shm_perm);
  593                 break;
  594         case IPC_SET: {
  595                 struct shmid_ds *shmid;
  596 
  597                 shmid = (struct shmid_ds *)buf;
  598                 error = ipcperm(td, &shmseg->u.shm_perm, IPC_M);
  599                 if (error)
  600                         goto done2;
  601                 shmseg->u.shm_perm.uid = shmid->shm_perm.uid;
  602                 shmseg->u.shm_perm.gid = shmid->shm_perm.gid;
  603                 shmseg->u.shm_perm.mode =
  604                     (shmseg->u.shm_perm.mode & ~ACCESSPERMS) |
  605                     (shmid->shm_perm.mode & ACCESSPERMS);
  606                 shmseg->u.shm_ctime = time_second;
  607                 break;
  608         }
  609         case IPC_RMID:
  610                 error = ipcperm(td, &shmseg->u.shm_perm, IPC_M);
  611                 if (error)
  612                         goto done2;
  613                 shmseg->u.shm_perm.key = IPC_PRIVATE;
  614                 shmseg->u.shm_perm.mode |= SHMSEG_REMOVED;
  615                 if (shmseg->u.shm_nattch <= 0) {
  616                         shm_deallocate_segment(shmseg);
  617                         shm_last_free = IPCID_TO_IX(shmid);
  618                 }
  619                 break;
  620 #if 0
  621         case SHM_LOCK:
  622         case SHM_UNLOCK:
  623 #endif
  624         default:
  625                 error = EINVAL;
  626                 break;
  627         }
  628 done2:
  629         mtx_unlock(&Giant);
  630         return (error);
  631 }
  632 
  633 int
  634 shmctl(td, uap)
  635         struct thread *td;
  636         struct shmctl_args *uap;
  637 {
  638         int error = 0;
  639         struct shmid_ds buf;
  640         size_t bufsz;
  641         
  642         /* IPC_SET needs to copyin the buffer before calling kern_shmctl */
  643         if (uap->cmd == IPC_SET) {
  644                 if ((error = copyin(uap->buf, &buf, sizeof(struct shmid_ds))))
  645                         goto done;
  646         }
  647         
  648         error = kern_shmctl(td, uap->shmid, uap->cmd, (void *)&buf, &bufsz);
  649         if (error)
  650                 goto done;
  651         
  652         /* Cases in which we need to copyout */
  653         switch (uap->cmd) {
  654         case IPC_INFO:
  655         case SHM_INFO:
  656         case SHM_STAT:
  657         case IPC_STAT:
  658                 error = copyout(&buf, uap->buf, bufsz);
  659                 break;
  660         }
  661 
  662 done:
  663         if (error) {
  664                 /* Invalidate the return value */
  665                 td->td_retval[0] = -1;
  666         }
  667         return (error);
  668 }
  669 
  670 
  671 #ifndef _SYS_SYSPROTO_H_
  672 struct shmget_args {
  673         key_t key;
  674         size_t size;
  675         int shmflg;
  676 };
  677 #endif
  678 static int
  679 shmget_existing(td, uap, mode, segnum)
  680         struct thread *td;
  681         struct shmget_args *uap;
  682         int mode;
  683         int segnum;
  684 {
  685         struct shmid_kernel *shmseg;
  686         int error;
  687 
  688         shmseg = &shmsegs[segnum];
  689         if (shmseg->u.shm_perm.mode & SHMSEG_REMOVED) {
  690                 /*
  691                  * This segment is in the process of being allocated.  Wait
  692                  * until it's done, and look the key up again (in case the
  693                  * allocation failed or it was freed).
  694                  */
  695                 shmseg->u.shm_perm.mode |= SHMSEG_WANTED;
  696                 error = tsleep(shmseg, PLOCK | PCATCH, "shmget", 0);
  697                 if (error)
  698                         return (error);
  699                 return (EAGAIN);
  700         }
  701         if ((uap->shmflg & (IPC_CREAT | IPC_EXCL)) == (IPC_CREAT | IPC_EXCL))
  702                 return (EEXIST);
  703 #ifdef MAC
  704         error = mac_check_sysv_shmget(td->td_ucred, shmseg, uap->shmflg);
  705         if (error != 0)
  706                 return (error);
  707 #endif
  708         if (uap->size && uap->size > shmseg->u.shm_segsz)
  709                 return (EINVAL);
  710         td->td_retval[0] = IXSEQ_TO_IPCID(segnum, shmseg->u.shm_perm);
  711         return (0);
  712 }
  713 
  714 static int
  715 shmget_allocate_segment(td, uap, mode)
  716         struct thread *td;
  717         struct shmget_args *uap;
  718         int mode;
  719 {
  720         int i, segnum, shmid, size;
  721         struct ucred *cred = td->td_ucred;
  722         struct shmid_kernel *shmseg;
  723         vm_object_t shm_object;
  724 
  725         GIANT_REQUIRED;
  726 
  727         if (uap->size < shminfo.shmmin || uap->size > shminfo.shmmax)
  728                 return (EINVAL);
  729         if (shm_nused >= shminfo.shmmni) /* Any shmids left? */
  730                 return (ENOSPC);
  731         size = round_page(uap->size);
  732         if (shm_committed + btoc(size) > shminfo.shmall)
  733                 return (ENOMEM);
  734         if (shm_last_free < 0) {
  735                 shmrealloc();   /* Maybe expand the shmsegs[] array. */
  736                 for (i = 0; i < shmalloced; i++)
  737                         if (shmsegs[i].u.shm_perm.mode & SHMSEG_FREE)
  738                                 break;
  739                 if (i == shmalloced)
  740                         return (ENOSPC);
  741                 segnum = i;
  742         } else  {
  743                 segnum = shm_last_free;
  744                 shm_last_free = -1;
  745         }
  746         shmseg = &shmsegs[segnum];
  747         /*
  748          * In case we sleep in malloc(), mark the segment present but deleted
  749          * so that noone else tries to create the same key.
  750          */
  751         shmseg->u.shm_perm.mode = SHMSEG_ALLOCATED | SHMSEG_REMOVED;
  752         shmseg->u.shm_perm.key = uap->key;
  753         shmseg->u.shm_perm.seq = (shmseg->u.shm_perm.seq + 1) & 0x7fff;
  754         shmid = IXSEQ_TO_IPCID(segnum, shmseg->u.shm_perm);
  755         
  756         /*
  757          * We make sure that we have allocated a pager before we need
  758          * to.
  759          */
  760         if (shm_use_phys) {
  761                 shm_object =
  762                     vm_pager_allocate(OBJT_PHYS, 0, size, VM_PROT_DEFAULT, 0);
  763         } else {
  764                 shm_object =
  765                     vm_pager_allocate(OBJT_SWAP, 0, size, VM_PROT_DEFAULT, 0);
  766         }
  767         VM_OBJECT_LOCK(shm_object);
  768         vm_object_clear_flag(shm_object, OBJ_ONEMAPPING);
  769         vm_object_set_flag(shm_object, OBJ_NOSPLIT);
  770         VM_OBJECT_UNLOCK(shm_object);
  771 
  772         shmseg->u.shm_internal = shm_object;
  773         shmseg->u.shm_perm.cuid = shmseg->u.shm_perm.uid = cred->cr_uid;
  774         shmseg->u.shm_perm.cgid = shmseg->u.shm_perm.gid = cred->cr_gid;
  775         shmseg->u.shm_perm.mode = (shmseg->u.shm_perm.mode & SHMSEG_WANTED) |
  776             (mode & ACCESSPERMS) | SHMSEG_ALLOCATED;
  777         shmseg->u.shm_segsz = uap->size;
  778         shmseg->u.shm_cpid = td->td_proc->p_pid;
  779         shmseg->u.shm_lpid = shmseg->u.shm_nattch = 0;
  780         shmseg->u.shm_atime = shmseg->u.shm_dtime = 0;
  781 #ifdef MAC
  782         mac_create_sysv_shm(cred, shmseg);
  783 #endif
  784         shmseg->u.shm_ctime = time_second;
  785         shm_committed += btoc(size);
  786         shm_nused++;
  787         if (shmseg->u.shm_perm.mode & SHMSEG_WANTED) {
  788                 /*
  789                  * Somebody else wanted this key while we were asleep.  Wake
  790                  * them up now.
  791                  */
  792                 shmseg->u.shm_perm.mode &= ~SHMSEG_WANTED;
  793                 wakeup(shmseg);
  794         }
  795         td->td_retval[0] = shmid;
  796         return (0);
  797 }
  798 
  799 int
  800 shmget(td, uap)
  801         struct thread *td;
  802         struct shmget_args *uap;
  803 {
  804         int segnum, mode;
  805         int error;
  806 
  807         if (!jail_sysvipc_allowed && jailed(td->td_ucred))
  808                 return (ENOSYS);
  809         mtx_lock(&Giant);
  810         mode = uap->shmflg & ACCESSPERMS;
  811         if (uap->key != IPC_PRIVATE) {
  812         again:
  813                 segnum = shm_find_segment_by_key(uap->key);
  814                 if (segnum >= 0) {
  815                         error = shmget_existing(td, uap, mode, segnum);
  816                         if (error == EAGAIN)
  817                                 goto again;
  818                         goto done2;
  819                 }
  820                 if ((uap->shmflg & IPC_CREAT) == 0) {
  821                         error = ENOENT;
  822                         goto done2;
  823                 }
  824         }
  825         error = shmget_allocate_segment(td, uap, mode);
  826 done2:
  827         mtx_unlock(&Giant);
  828         return (error);
  829 }
  830 
  831 int
  832 shmsys(td, uap)
  833         struct thread *td;
  834         /* XXX actually varargs. */
  835         struct shmsys_args /* {
  836                 int     which;
  837                 int     a2;
  838                 int     a3;
  839                 int     a4;
  840         } */ *uap;
  841 {
  842 #if defined(__i386__) && (defined(COMPAT_FREEBSD4) || defined(COMPAT_43))
  843         int error;
  844 
  845         if (!jail_sysvipc_allowed && jailed(td->td_ucred))
  846                 return (ENOSYS);
  847         if (uap->which < 0 ||
  848             uap->which >= sizeof(shmcalls)/sizeof(shmcalls[0]))
  849                 return (EINVAL);
  850         mtx_lock(&Giant);
  851         error = (*shmcalls[uap->which])(td, &uap->a2);
  852         mtx_unlock(&Giant);
  853         return (error);
  854 #else
  855         return (nosys(td, NULL));
  856 #endif
  857 }
  858 
  859 static void
  860 shmfork_myhook(p1, p2)
  861         struct proc *p1, *p2;
  862 {
  863         struct shmmap_state *shmmap_s;
  864         size_t size;
  865         int i;
  866 
  867         mtx_lock(&Giant);
  868         size = shminfo.shmseg * sizeof(struct shmmap_state);
  869         shmmap_s = malloc(size, M_SHM, M_WAITOK);
  870         bcopy(p1->p_vmspace->vm_shm, shmmap_s, size);
  871         p2->p_vmspace->vm_shm = shmmap_s;
  872         for (i = 0; i < shminfo.shmseg; i++, shmmap_s++)
  873                 if (shmmap_s->shmid != -1)
  874                         shmsegs[IPCID_TO_IX(shmmap_s->shmid)].u.shm_nattch++;
  875         mtx_unlock(&Giant);
  876 }
  877 
  878 static void
  879 shmexit_myhook(struct vmspace *vm)
  880 {
  881         struct shmmap_state *base, *shm;
  882         int i;
  883 
  884         if ((base = vm->vm_shm) != NULL) {
  885                 vm->vm_shm = NULL;
  886                 mtx_lock(&Giant);
  887                 for (i = 0, shm = base; i < shminfo.shmseg; i++, shm++) {
  888                         if (shm->shmid != -1)
  889                                 shm_delete_mapping(vm, shm);
  890                 }
  891                 mtx_unlock(&Giant);
  892                 free(base, M_SHM);
  893         }
  894 }
  895 
  896 static void
  897 shmrealloc(void)
  898 {
  899         int i;
  900         struct shmid_kernel *newsegs;
  901 
  902         if (shmalloced >= shminfo.shmmni)
  903                 return;
  904 
  905         newsegs = malloc(shminfo.shmmni * sizeof(*newsegs), M_SHM, M_WAITOK);
  906         if (newsegs == NULL)
  907                 return;
  908         for (i = 0; i < shmalloced; i++)
  909                 bcopy(&shmsegs[i], &newsegs[i], sizeof(newsegs[0]));
  910         for (; i < shminfo.shmmni; i++) {
  911                 shmsegs[i].u.shm_perm.mode = SHMSEG_FREE;
  912                 shmsegs[i].u.shm_perm.seq = 0;
  913 #ifdef MAC
  914                 mac_init_sysv_shm(&shmsegs[i]);
  915 #endif
  916         }
  917         free(shmsegs, M_SHM);
  918         shmsegs = newsegs;
  919         shmalloced = shminfo.shmmni;
  920 }
  921 
  922 static void
  923 shminit()
  924 {
  925         int i;
  926 
  927         TUNABLE_ULONG_FETCH("kern.ipc.shmmaxpgs", &shminfo.shmall);
  928         for (i = PAGE_SIZE; i > 0; i--) {
  929                 shminfo.shmmax = shminfo.shmall * i;
  930                 if (shminfo.shmmax >= shminfo.shmall)
  931                         break;
  932         }
  933         TUNABLE_ULONG_FETCH("kern.ipc.shmmin", &shminfo.shmmin);
  934         TUNABLE_ULONG_FETCH("kern.ipc.shmmni", &shminfo.shmmni);
  935         TUNABLE_ULONG_FETCH("kern.ipc.shmseg", &shminfo.shmseg);
  936         TUNABLE_INT_FETCH("kern.ipc.shm_use_phys", &shm_use_phys);
  937 
  938         shmalloced = shminfo.shmmni;
  939         shmsegs = malloc(shmalloced * sizeof(shmsegs[0]), M_SHM, M_WAITOK);
  940         if (shmsegs == NULL)
  941                 panic("cannot allocate initial memory for sysvshm");
  942         for (i = 0; i < shmalloced; i++) {
  943                 shmsegs[i].u.shm_perm.mode = SHMSEG_FREE;
  944                 shmsegs[i].u.shm_perm.seq = 0;
  945 #ifdef MAC
  946                 mac_init_sysv_shm(&shmsegs[i]);
  947 #endif
  948         }
  949         shm_last_free = 0;
  950         shm_nused = 0;
  951         shm_committed = 0;
  952         shmexit_hook = &shmexit_myhook;
  953         shmfork_hook = &shmfork_myhook;
  954 }
  955 
  956 static int
  957 shmunload()
  958 {
  959 #ifdef MAC
  960         int i;  
  961 #endif
  962 
  963         if (shm_nused > 0)
  964                 return (EBUSY);
  965 
  966 #ifdef MAC
  967         for (i = 0; i < shmalloced; i++)
  968                 mac_destroy_sysv_shm(&shmsegs[i]);
  969 #endif
  970         free(shmsegs, M_SHM);
  971         shmexit_hook = NULL;
  972         shmfork_hook = NULL;
  973         return (0);
  974 }
  975 
  976 static int
  977 sysctl_shmsegs(SYSCTL_HANDLER_ARGS)
  978 {
  979 
  980         return (SYSCTL_OUT(req, shmsegs, shmalloced * sizeof(shmsegs[0])));
  981 }
  982 
  983 static int
  984 sysvshm_modload(struct module *module, int cmd, void *arg)
  985 {
  986         int error = 0;
  987 
  988         switch (cmd) {
  989         case MOD_LOAD:
  990                 shminit();
  991                 break;
  992         case MOD_UNLOAD:
  993                 error = shmunload();
  994                 break;
  995         case MOD_SHUTDOWN:
  996                 break;
  997         default:
  998                 error = EINVAL;
  999                 break;
 1000         }
 1001         return (error);
 1002 }
 1003 
 1004 static moduledata_t sysvshm_mod = {
 1005         "sysvshm",
 1006         &sysvshm_modload,
 1007         NULL
 1008 };
 1009 
 1010 SYSCALL_MODULE_HELPER(shmsys);
 1011 SYSCALL_MODULE_HELPER(shmat);
 1012 SYSCALL_MODULE_HELPER(shmctl);
 1013 SYSCALL_MODULE_HELPER(shmdt);
 1014 SYSCALL_MODULE_HELPER(shmget);
 1015 
 1016 DECLARE_MODULE(sysvshm, sysvshm_mod,
 1017         SI_SUB_SYSV_SHM, SI_ORDER_FIRST);
 1018 MODULE_VERSION(sysvshm, 1);

Cache object: 91105436a1c5fab813c1c4a0298e2b08


[ 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.