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/bsd/kern/posix_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 /*
    2  * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
    3  *
    4  * @APPLE_LICENSE_HEADER_START@
    5  * 
    6  * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
    7  * 
    8  * This file contains Original Code and/or Modifications of Original Code
    9  * as defined in and that are subject to the Apple Public Source License
   10  * Version 2.0 (the 'License'). You may not use this file except in
   11  * compliance with the License. Please obtain a copy of the License at
   12  * http://www.opensource.apple.com/apsl/ and read it before using this
   13  * file.
   14  * 
   15  * The Original Code and all software distributed under the License are
   16  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
   17  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
   18  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
   19  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
   20  * Please see the License for the specific language governing rights and
   21  * limitations under the License.
   22  * 
   23  * @APPLE_LICENSE_HEADER_END@
   24  */
   25 /*
   26  *      Copyright (c) 1990, 1996-1998 Apple Computer, Inc.
   27  *      All Rights Reserved.
   28  */
   29 /*
   30  * posix_shm.c : Support for POSIX shared memory APIs
   31  *
   32  *      File:   posix_shm.c
   33  *      Author: Ananthakrishna Ramesh
   34  *
   35  * HISTORY
   36  * 2-Sep-1999   A.Ramesh
   37  *      Created for MacOSX
   38  *
   39  */
   40 
   41 #include <sys/cdefs.h>
   42 #include <sys/param.h>
   43 #include <sys/systm.h>
   44 #include <sys/kernel.h>
   45 #include <sys/file.h>
   46 #include <sys/filedesc.h>
   47 #include <sys/stat.h>
   48 #include <sys/buf.h>
   49 #include <sys/proc.h>
   50 #include <sys/mount.h>
   51 #include <sys/namei.h>
   52 #include <sys/vnode.h>
   53 #include <sys/ioctl.h>
   54 #include <sys/tty.h>
   55 #include <sys/malloc.h>
   56 #include <sys/mman.h>
   57 #include <sys/stat.h>
   58 #include <mach/mach_types.h>
   59 #include <mach/vm_prot.h>
   60 #include <mach/vm_inherit.h>
   61 #include <mach/kern_return.h>
   62 #include <mach/memory_object_control.h>
   63 
   64 
   65 #define PSHMNAMLEN      31      /* maximum name segment length we bother with */
   66 
   67 struct pshminfo {
   68         unsigned int    pshm_flags;
   69         unsigned int    pshm_usecount;
   70         off_t           pshm_length;
   71         mode_t          pshm_mode;
   72         uid_t           pshm_uid;
   73         gid_t           pshm_gid;
   74         char            pshm_name[PSHMNAMLEN + 1];      /* segment name */
   75         void *          pshm_memobject;
   76 #if DIAGNOSTIC
   77         unsigned int    pshm_readcount;
   78         unsigned int    pshm_writecount;
   79         struct proc *   pshm_proc;
   80 #endif /* DIAGNOSTIC */
   81 };
   82 #define PSHMINFO_NULL (struct pshminfo *)0
   83 
   84 #define PSHM_NONE       1
   85 #define PSHM_DEFINED    2
   86 #define PSHM_ALLOCATED  4
   87 #define PSHM_MAPPED     8
   88 #define PSHM_INUSE      0x10
   89 #define PSHM_REMOVED    0x20
   90 #define PSHM_INCREATE   0x40
   91 #define PSHM_INDELETE   0x80
   92 
   93 struct  pshmcache {
   94         LIST_ENTRY(pshmcache) pshm_hash;        /* hash chain */
   95         struct  pshminfo *pshminfo;             /* vnode the name refers to */
   96         int     pshm_nlen;              /* length of name */
   97         char    pshm_name[PSHMNAMLEN + 1];      /* segment name */
   98 };
   99 #define PSHMCACHE_NULL (struct pshmcache *)0
  100 
  101 struct  pshmstats {
  102         long    goodhits;               /* hits that we can really use */
  103         long    neghits;                /* negative hits that we can use */
  104         long    badhits;                /* hits we must drop */
  105         long    falsehits;              /* hits with id mismatch */
  106         long    miss;           /* misses */
  107         long    longnames;              /* long names that ignore cache */
  108 };
  109 
  110 struct pshmname {
  111         char    *pshm_nameptr;  /* pointer to looked up name */
  112         long    pshm_namelen;   /* length of looked up component */
  113         u_long  pshm_hash;      /* hash value of looked up name */
  114 };
  115 
  116 struct pshmnode {
  117         off_t  mapp_addr;
  118         size_t  map_size;
  119         struct pshminfo *pinfo;
  120         unsigned int    pshm_usecount;
  121 #if DIAGNOSTIC
  122         unsigned int readcnt;
  123         unsigned int writecnt;
  124 #endif
  125 };
  126 #define PSHMNODE_NULL (struct pshmnode *)0
  127 
  128 
  129 #define PSHMHASH(pnp) \
  130         (&pshmhashtbl[(pnp)->pshm_hash & pshmhash])
  131 LIST_HEAD(pshmhashhead, pshmcache) *pshmhashtbl;        /* Hash Table */
  132 u_long  pshmhash;                               /* size of hash table - 1 */
  133 long    pshmnument;                     /* number of cache entries allocated */
  134 struct pshmstats pshmstats;             /* cache effectiveness statistics */
  135 
  136 static int pshm_read  __P((struct file *fp, struct uio *uio,
  137                     struct ucred *cred, int flags, struct proc *p));
  138 static int pshm_write  __P((struct file *fp, struct uio *uio,
  139                     struct ucred *cred, int flags, struct proc *p));
  140 static int pshm_ioctl  __P((struct file *fp, u_long com,
  141                     caddr_t data, struct proc *p));
  142 static int pshm_select  __P((struct file *fp, int which, void *wql,
  143                     struct proc *p));
  144 static int pshm_closefile  __P((struct file *fp, struct proc *p));
  145 
  146 static int pshm_kqfilter __P((struct file *fp, struct knote *kn, struct proc *p));
  147 
  148 struct  fileops pshmops =
  149         { pshm_read, pshm_write, pshm_ioctl, pshm_select, pshm_closefile, pshm_kqfilter };
  150 
  151 /*
  152  * Lookup an entry in the cache 
  153  * 
  154  * 
  155  * status of -1 is returned if matches
  156  * If the lookup determines that the name does not exist
  157  * (negative cacheing), a status of ENOENT is returned. If the lookup
  158  * fails, a status of zero is returned.
  159  */
  160 
  161 int
  162 pshm_cache_search(pshmp, pnp, pcache)
  163         struct pshminfo **pshmp;
  164         struct pshmname *pnp;
  165         struct pshmcache **pcache;
  166 {
  167         register struct pshmcache *pcp, *nnp;
  168         register struct pshmhashhead *pcpp;
  169 
  170         if (pnp->pshm_namelen > PSHMNAMLEN) {
  171                 pshmstats.longnames++;
  172                 return (0);
  173         }
  174 
  175         pcpp = PSHMHASH(pnp);
  176         for (pcp = pcpp->lh_first; pcp != 0; pcp = nnp) {
  177                 nnp = pcp->pshm_hash.le_next;
  178                 if (pcp->pshm_nlen == pnp->pshm_namelen &&
  179                     !bcmp(pcp->pshm_name, pnp->pshm_nameptr,                                            (u_int)pcp-> pshm_nlen))
  180                         break;
  181         }
  182 
  183         if (pcp == 0) {
  184                 pshmstats.miss++;
  185                 return (0);
  186         }
  187 
  188         /* We found a "positive" match, return the vnode */
  189         if (pcp->pshminfo) {
  190                 pshmstats.goodhits++;
  191                 /* TOUCH(ncp); */
  192                 *pshmp = pcp->pshminfo;
  193                 *pcache = pcp;
  194                 return (-1);
  195         }
  196 
  197         /*
  198          * We found a "negative" match, ENOENT notifies client of this match.
  199          * The nc_vpid field records whether this is a whiteout.
  200          */
  201         pshmstats.neghits++;
  202         return (ENOENT);
  203 }
  204 
  205 /*
  206  * Add an entry to the cache.
  207  */
  208 int
  209 pshm_cache_add(pshmp, pnp)
  210         struct pshminfo *pshmp;
  211         struct pshmname *pnp;
  212 {
  213         register struct pshmcache *pcp;
  214         register struct pshmhashhead *pcpp;
  215         struct pshminfo *dpinfo;
  216         struct pshmcache *dpcp;
  217 
  218 #if DIAGNOSTIC
  219         if (pnp->pshm_namelen > NCHNAMLEN)
  220                 panic("cache_enter: name too long");
  221 #endif
  222 
  223         /*
  224          * We allocate a new entry if we are less than the maximum
  225          * allowed and the one at the front of the LRU list is in use.
  226          * Otherwise we use the one at the front of the LRU list.
  227          */
  228         pcp = (struct pshmcache *)_MALLOC(sizeof(struct pshmcache), M_SHM, M_WAITOK);
  229         /*  if the entry has already been added by some one else return */
  230         if (pshm_cache_search(&dpinfo, pnp, &dpcp) == -1) {
  231                 _FREE(pcp, M_SHM);
  232                 return(EEXIST);
  233         }
  234         pshmnument++;
  235 
  236         bzero(pcp, sizeof(struct pshmcache));
  237         /*
  238          * Fill in cache info, if vp is NULL this is a "negative" cache entry.
  239          * For negative entries, we have to record whether it is a whiteout.
  240          * the whiteout flag is stored in the nc_vpid field which is
  241          * otherwise unused.
  242          */
  243         pcp->pshminfo = pshmp;
  244         pcp->pshm_nlen = pnp->pshm_namelen;
  245         bcopy(pnp->pshm_nameptr, pcp->pshm_name, (unsigned)pcp->pshm_nlen);
  246         pcpp = PSHMHASH(pnp);
  247 #if DIAGNOSTIC
  248         {
  249                 register struct pshmcache *p;
  250 
  251                 for (p = pcpp->lh_first; p != 0; p = p->pshm_hash.le_next)
  252                         if (p == pcp)
  253                                 panic("cache_enter: duplicate");
  254         }
  255 #endif
  256         LIST_INSERT_HEAD(pcpp, pcp, pshm_hash);
  257         return(0);
  258 }
  259 
  260 /*
  261  * Name cache initialization, from vfs_init() when we are booting
  262  */
  263 void
  264 pshm_cache_init()
  265 {
  266         pshmhashtbl = hashinit(desiredvnodes, M_SHM, &pshmhash);
  267 }
  268 
  269 /*
  270  * Invalidate a all entries to particular vnode.
  271  * 
  272  * We actually just increment the v_id, that will do it. The entries will
  273  * be purged by lookup as they get found. If the v_id wraps around, we
  274  * need to ditch the entire cache, to avoid confusion. No valid vnode will
  275  * ever have (v_id == 0).
  276  */
  277 void
  278 pshm_cache_purge(void)
  279 {
  280         struct pshmcache *pcp;
  281         struct pshmhashhead *pcpp;
  282 
  283         for (pcpp = &pshmhashtbl[pshmhash]; pcpp >= pshmhashtbl; pcpp--) {
  284                 while (pcp = pcpp->lh_first)
  285                         pshm_cache_delete(pcp);
  286         }
  287 }
  288 
  289 pshm_cache_delete(pcp)
  290         struct pshmcache *pcp;
  291 {
  292 #if DIAGNOSTIC
  293         if (pcp->pshm_hash.le_prev == 0)
  294                 panic("namecache purge le_prev");
  295         if (pcp->pshm_hash.le_next == pcp)
  296                 panic("namecache purge le_next");
  297 #endif /* DIAGNOSTIC */
  298         LIST_REMOVE(pcp, pshm_hash);
  299         pcp->pshm_hash.le_prev = 0;     
  300         pshmnument--;
  301 }
  302 
  303 
  304 struct shm_open_args {
  305         const char *name;
  306         int oflag;
  307         int mode;
  308 };
  309 
  310 int
  311 shm_open(p, uap, retval)
  312         struct proc *p;
  313         register struct shm_open_args *uap;
  314         register_t *retval;
  315 {
  316         register struct filedesc *fdp = p->p_fd;
  317         register struct file *fp;
  318         register struct vnode *vp;
  319         int  i;
  320         struct file *nfp;
  321         int type, indx, error;
  322         struct pshmname nd;
  323         struct pshminfo *pinfo;
  324         extern struct fileops pshmops;
  325         char * pnbuf;
  326         char * nameptr;
  327         char * cp;
  328         size_t pathlen, plen;
  329         int fmode ;
  330         int cmode = uap->mode;
  331         int incache = 0;
  332         struct pshmnode * pnode = PSHMNODE_NULL;
  333         struct pshmcache * pcache = PSHMCACHE_NULL;
  334         int pinfo_alloc=0;
  335 
  336 
  337         pinfo = PSHMINFO_NULL;
  338 
  339         MALLOC_ZONE(pnbuf, caddr_t,
  340                         MAXPATHLEN, M_NAMEI, M_WAITOK);
  341         pathlen = MAXPATHLEN;
  342         error = copyinstr((void *)uap->name, (void *)pnbuf,
  343                 MAXPATHLEN, &pathlen);
  344         if (error) {
  345                 goto bad;
  346         }
  347         if (pathlen > PSHMNAMLEN) {
  348                 error = ENAMETOOLONG;
  349                 goto bad;
  350         }
  351 
  352 
  353 #ifdef PSXSHM_NAME_RESTRICT
  354         nameptr = pnbuf;
  355         if (*nameptr == '/') {
  356                 while (*(nameptr++) == '/') {
  357                         plen--;
  358                         error = EINVAL;
  359                         goto bad;
  360                 }
  361         } else {
  362                 error = EINVAL;
  363                 goto bad;
  364         }
  365 #endif /* PSXSHM_NAME_RESTRICT */
  366 
  367         plen = pathlen;
  368         nameptr = pnbuf;
  369         nd.pshm_nameptr = nameptr;
  370         nd.pshm_namelen = plen;
  371         nd. pshm_hash =0;
  372 
  373         for (cp = nameptr, i=1; *cp != 0 && i <= plen; i++, cp++) {
  374                nd.pshm_hash += (unsigned char)*cp * i;
  375         }
  376 
  377         error = pshm_cache_search(&pinfo, &nd, &pcache);
  378 
  379         if (error == ENOENT) {
  380                 error = EINVAL;
  381                 goto bad;
  382 
  383         }
  384         if (!error) {
  385                 incache = 0;
  386         } else
  387                 incache = 1;
  388         fmode = FFLAGS(uap->oflag);
  389         if ((fmode & (FREAD | FWRITE))==0) {
  390                 error = EINVAL;
  391                 goto bad;
  392         }
  393 
  394         if (error = falloc(p, &nfp, &indx))
  395                 goto bad;
  396         fp = nfp;
  397 
  398         cmode &=  ALLPERMS;
  399 
  400         if (fmode & O_CREAT) {
  401                 if ((fmode & O_EXCL) && incache) {
  402                         /* shm obj exists and opened O_EXCL */
  403 #if notyet
  404                         if (pinfo->pshm_flags & PSHM_INDELETE) {
  405                         }
  406 #endif 
  407                         error = EEXIST;
  408                         goto bad1;
  409                 } 
  410                 if (!incache) {
  411                     /*  create a new one */
  412                     pinfo = (struct pshminfo *)_MALLOC(sizeof(struct pshminfo), M_SHM, M_WAITOK);
  413                     bzero(pinfo, sizeof(struct pshminfo));
  414                         pinfo_alloc = 1;
  415                     pinfo->pshm_flags = PSHM_DEFINED | PSHM_INCREATE;
  416                     pinfo->pshm_usecount = 1;
  417                     pinfo->pshm_mode = cmode;
  418                     pinfo->pshm_uid = p->p_ucred->cr_uid;
  419                     pinfo->pshm_gid = p->p_ucred->cr_gid;
  420                 } else {
  421                     /*  already exists */
  422                         if( pinfo->pshm_flags & PSHM_INDELETE) {
  423                             error = ENOENT;
  424                             goto bad1;
  425                         }       
  426                         if (error = pshm_access(pinfo, fmode, p->p_ucred, p))
  427                             goto bad1;
  428                 }
  429         } else {
  430                 if (!incache) {
  431                         /* O_CREAT  is not set and the shm obecj does not exist */
  432                         error = ENOENT;
  433                         goto bad1;
  434                 }
  435                 if( pinfo->pshm_flags & PSHM_INDELETE) {
  436                         error = ENOENT;
  437                         goto bad1;
  438                 }       
  439                 if (error = pshm_access(pinfo, fmode, p->p_ucred, p))
  440                         goto bad1;
  441         }
  442         if (fmode & O_TRUNC) {
  443                 error = EINVAL;
  444                 goto bad2;
  445         }
  446 #if DIAGNOSTIC 
  447         if (fmode & FWRITE)
  448                 pinfo->pshm_writecount++;
  449         if (fmode & FREAD)
  450                 pinfo->pshm_readcount++;
  451 #endif
  452         pnode = (struct pshmnode *)_MALLOC(sizeof(struct pshmnode), M_SHM, M_WAITOK);
  453         bzero(pnode, sizeof(struct pshmnode));
  454 
  455         if (!incache) {
  456                 if (error = pshm_cache_add(pinfo, &nd)) {
  457                 goto bad3;
  458                 }
  459         }
  460         pinfo->pshm_flags &= ~PSHM_INCREATE;
  461         pinfo->pshm_usecount++;
  462         pnode->pinfo = pinfo;
  463         fp->f_flag = fmode & FMASK;
  464         fp->f_type = DTYPE_PSXSHM;
  465         fp->f_ops = &pshmops;
  466         fp->f_data = (caddr_t)pnode;
  467         *fdflags(p, indx) &= ~UF_RESERVED;
  468         *retval = indx;
  469         FREE_ZONE(pnbuf, MAXPATHLEN, M_NAMEI);
  470         return (0);
  471 bad3:
  472         _FREE(pnode, M_SHM);
  473                 
  474 bad2:
  475         if (pinfo_alloc)
  476                 _FREE(pinfo, M_SHM);
  477 bad1:
  478         fdrelse(p, indx);
  479         ffree(nfp);
  480 bad:
  481         FREE_ZONE(pnbuf, MAXPATHLEN, M_NAMEI);
  482         return (error);
  483 }
  484 
  485 
  486 /* ARGSUSED */
  487 int
  488 pshm_truncate(p, fp, fd, length, retval)
  489         struct proc *p;
  490         struct file *fp;
  491         int fd;
  492         off_t length;
  493         register_t *retval;
  494 {
  495         struct pshminfo * pinfo;
  496         struct pshmnode * pnode ;
  497         kern_return_t kret;
  498         vm_offset_t user_addr;
  499         void * mem_object;
  500         vm_size_t size;
  501 
  502         if (fp->f_type != DTYPE_PSXSHM) {
  503                 return(EINVAL);
  504         }
  505         
  506 
  507         if (((pnode = (struct pshmnode *)fp->f_data)) == PSHMNODE_NULL )
  508                 return(EINVAL);
  509 
  510         if ((pinfo = pnode->pinfo) == PSHMINFO_NULL)
  511                 return(EINVAL);
  512         if ((pinfo->pshm_flags & (PSHM_DEFINED | PSHM_ALLOCATED)) 
  513                         != PSHM_DEFINED) {
  514                 return(EINVAL);
  515         }
  516 
  517         size = round_page_64(length);
  518         kret = vm_allocate(current_map(), &user_addr, size, TRUE);
  519         if (kret != KERN_SUCCESS) 
  520                 goto out;
  521 
  522         kret = mach_make_memory_entry (current_map(), &size,
  523                         user_addr, VM_PROT_DEFAULT, &mem_object, 0);
  524 
  525         if (kret != KERN_SUCCESS) 
  526                 goto out;
  527         
  528         vm_deallocate(current_map(), user_addr, size);
  529 
  530         pinfo->pshm_flags &= ~PSHM_DEFINED;
  531         pinfo->pshm_flags = PSHM_ALLOCATED;
  532         pinfo->pshm_memobject = mem_object;
  533         pinfo->pshm_length = size;
  534         return(0);
  535 
  536 out:
  537         switch (kret) {
  538         case KERN_INVALID_ADDRESS:
  539         case KERN_NO_SPACE:
  540                 return (ENOMEM);
  541         case KERN_PROTECTION_FAILURE:
  542                 return (EACCES);
  543         default:
  544                 return (EINVAL);
  545         
  546         }
  547 }
  548 
  549 int
  550 pshm_stat(pnode, sb)
  551 struct pshmnode *pnode;
  552 struct stat *sb;
  553 {
  554         struct pshminfo *pinfo;
  555         
  556         if ((pinfo = pnode->pinfo) == PSHMINFO_NULL)
  557                 return(EINVAL);
  558 
  559         bzero(sb, sizeof(struct stat)); 
  560         sb->st_mode = pinfo->pshm_mode;
  561         sb->st_uid = pinfo->pshm_uid;
  562         sb->st_gid = pinfo->pshm_gid;
  563         sb->st_size = pinfo->pshm_length;
  564 
  565         return(0);
  566 }
  567 
  568 int
  569 pshm_access(struct pshminfo *pinfo, int mode, struct ucred *cred, struct proc *p)
  570 {
  571         mode_t mask;
  572         register gid_t *gp;
  573         int i, error;
  574 
  575         /* Otherwise, user id 0 always gets access. */
  576         if (cred->cr_uid == 0)
  577                 return (0);
  578 
  579         mask = 0;
  580 
  581         /* Otherwise, check the owner. */
  582         if (cred->cr_uid == pinfo->pshm_uid) {
  583                 if (mode & FREAD)
  584                         mask |= S_IRUSR;
  585                 if (mode & FWRITE)
  586                         mask |= S_IWUSR;
  587                 return ((pinfo->pshm_mode & mask) == mask ? 0 : EACCES);
  588         }
  589 
  590         /* Otherwise, check the groups. */
  591         for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++)
  592                 if (pinfo->pshm_gid == *gp) {
  593                         if (mode & FREAD)
  594                                 mask |= S_IRGRP;
  595                         if (mode & FWRITE)
  596                                 mask |= S_IWGRP;
  597                         return ((pinfo->pshm_mode & mask) == mask ? 0 : EACCES);
  598                 }
  599 
  600         /* Otherwise, check everyone else. */
  601         if (mode & FREAD)
  602                 mask |= S_IROTH;
  603         if (mode & FWRITE)
  604                 mask |= S_IWOTH;
  605         return ((pinfo->pshm_mode & mask) == mask ? 0 : EACCES);
  606 }
  607 
  608 struct mmap_args {
  609                 caddr_t addr;
  610                 size_t len;
  611                 int prot;
  612                 int flags;
  613                 int fd;
  614 #ifdef DOUBLE_ALIGN_PARAMS
  615                 long pad;
  616 #endif
  617                 off_t pos;
  618 };
  619 
  620 int
  621 pshm_mmap(struct proc *p, struct mmap_args *uap, register_t *retval, struct file *fp, vm_size_t pageoff) 
  622 {
  623         vm_offset_t     user_addr = (vm_offset_t)uap->addr;
  624         vm_size_t       user_size = (vm_size_t)uap->len ;
  625         int prot = uap->prot;
  626         int flags = uap->flags;
  627         vm_object_offset_t file_pos = (vm_object_offset_t)uap->pos;
  628         int fd = uap->fd;
  629         vm_map_t        user_map;
  630         boolean_t       find_space,docow;
  631         kern_return_t   kret;
  632         struct pshminfo * pinfo;
  633         struct pshmnode * pnode;
  634         void * mem_object;
  635 
  636         if (user_size == 0) 
  637                 return(0);
  638 
  639         if ((flags & MAP_SHARED) == 0)
  640                 return(EINVAL);
  641 
  642 
  643         if ((prot & PROT_WRITE) && ((fp->f_flag & FWRITE) == 0)) {
  644                 return(EPERM);
  645         }
  646 
  647         if (((pnode = (struct pshmnode *)fp->f_data)) == PSHMNODE_NULL )
  648                 return(EINVAL);
  649 
  650         if ((pinfo = pnode->pinfo) == PSHMINFO_NULL)
  651                 return(EINVAL);
  652 
  653         if ((pinfo->pshm_flags & PSHM_ALLOCATED) != PSHM_ALLOCATED) {
  654                 return(EINVAL);
  655         }
  656         if (user_size > pinfo->pshm_length) {
  657                 return(EINVAL);
  658         }
  659         if ((off_t)user_size  + file_pos > pinfo->pshm_length) {
  660                 return(EINVAL);
  661         }
  662         if ((mem_object =  pinfo->pshm_memobject) == NULL) {
  663                 return(EINVAL);
  664         }
  665 
  666         
  667         user_map = current_map();
  668 
  669         if ((flags & MAP_FIXED) == 0) {
  670                 find_space = TRUE;
  671                 user_addr = round_page_32(user_addr); 
  672         } else {
  673                 if (user_addr != trunc_page_32(user_addr))
  674                         return (EINVAL);
  675                 find_space = FALSE;
  676                 (void) vm_deallocate(user_map, user_addr, user_size);
  677         }
  678         docow = FALSE;  
  679 
  680         kret = vm_map_64(user_map, &user_addr, user_size,
  681                         0, find_space, pinfo->pshm_memobject, file_pos, docow,
  682                         prot, VM_PROT_DEFAULT, 
  683                         VM_INHERIT_DEFAULT);
  684 
  685         if (kret != KERN_SUCCESS) 
  686                         goto out;
  687         kret = vm_inherit(user_map, user_addr, user_size,
  688                                 VM_INHERIT_SHARE);
  689         if (kret != KERN_SUCCESS) {
  690                 (void) vm_deallocate(user_map, user_addr, user_size);
  691                 goto out;
  692         }
  693         pnode->mapp_addr = user_addr;
  694         pnode->map_size = user_size;
  695         pinfo->pshm_flags |= (PSHM_MAPPED | PSHM_INUSE);
  696 out:
  697         switch (kret) {
  698         case KERN_SUCCESS:
  699                 *fdflags(p, fd) |= UF_MAPPED;
  700                 *retval = (register_t)(user_addr + pageoff);
  701                 return (0);
  702         case KERN_INVALID_ADDRESS:
  703         case KERN_NO_SPACE:
  704                 return (ENOMEM);
  705         case KERN_PROTECTION_FAILURE:
  706                 return (EACCES);
  707         default:
  708                 return (EINVAL);
  709         }
  710 
  711 }
  712 
  713 struct shm_unlink_args {
  714         const char *name;
  715 };
  716 
  717 int
  718 shm_unlink(p, uap, retval)
  719         struct proc *p;
  720         register struct shm_unlink_args *uap;
  721         register_t *retval;
  722 {
  723         register struct filedesc *fdp = p->p_fd;
  724         register struct file *fp;
  725         int flags, i;
  726         int error=0;
  727         struct pshmname nd;
  728         struct pshminfo *pinfo;
  729         extern struct fileops pshmops;
  730         char * pnbuf;
  731         char * nameptr;
  732         char * cp;
  733         size_t pathlen, plen;
  734         int fmode, cmode ;
  735         int incache = 0;
  736         struct pshmnode * pnode = PSHMNODE_NULL;
  737         struct pshmcache *pcache = PSHMCACHE_NULL;
  738         kern_return_t kret;
  739 
  740         pinfo = PSHMINFO_NULL;
  741 
  742         MALLOC_ZONE(pnbuf, caddr_t,
  743                         MAXPATHLEN, M_NAMEI, M_WAITOK);
  744         pathlen = MAXPATHLEN;
  745         error = copyinstr((void *)uap->name, (void *)pnbuf,
  746                 MAXPATHLEN, &pathlen);
  747         if (error) {
  748                 goto bad;
  749         }
  750         if (pathlen > PSHMNAMLEN) {
  751                 error = ENAMETOOLONG;
  752                 goto bad;
  753         }
  754 
  755 
  756 #ifdef PSXSHM_NAME_RESTRICT
  757         nameptr = pnbuf;
  758         if (*nameptr == '/') {
  759                 while (*(nameptr++) == '/') {
  760                         plen--;
  761                         error = EINVAL;
  762                         goto bad;
  763                 }
  764         } else {
  765                 error = EINVAL;
  766                 goto bad;
  767         }
  768 #endif /* PSXSHM_NAME_RESTRICT */
  769 
  770         plen = pathlen;
  771         nameptr = pnbuf;
  772         nd.pshm_nameptr = nameptr;
  773         nd.pshm_namelen = plen;
  774         nd. pshm_hash =0;
  775 
  776         for (cp = nameptr, i=1; *cp != 0 && i <= plen; i++, cp++) {
  777                nd.pshm_hash += (unsigned char)*cp * i;
  778         }
  779 
  780         error = pshm_cache_search(&pinfo, &nd, &pcache);
  781 
  782         if (error == ENOENT) {
  783                 error = EINVAL;
  784                 goto bad;
  785 
  786         }
  787         if (!error) {
  788                 error = EINVAL;
  789                 goto bad;
  790         } else
  791                 incache = 1;
  792 
  793         if ((pinfo->pshm_flags & (PSHM_DEFINED | PSHM_ALLOCATED))==0) {
  794                 return (EINVAL);
  795         }
  796 
  797         if (pinfo->pshm_flags & PSHM_INDELETE) {
  798                 error = 0;
  799                 goto bad;
  800         }
  801 
  802         if (pinfo->pshm_memobject == NULL) {
  803                 error = EINVAL;
  804                 goto bad;
  805         }
  806 
  807         pinfo->pshm_flags |= PSHM_INDELETE;
  808         pinfo->pshm_usecount--;
  809         kret = mach_destroy_memory_entry(pinfo->pshm_memobject);
  810         pshm_cache_delete(pcache);
  811         _FREE(pcache, M_SHM);
  812         pinfo->pshm_flags |= PSHM_REMOVED;
  813         error = 0;
  814 bad:
  815         FREE_ZONE(pnbuf, MAXPATHLEN, M_NAMEI);
  816         return (error);
  817 out:
  818         switch (kret) {
  819         case KERN_INVALID_ADDRESS:
  820         case KERN_PROTECTION_FAILURE:
  821                 return (EACCES);
  822         default:
  823                 return (EINVAL);
  824         }
  825 }
  826 
  827 int
  828 pshm_close(pnode, flags, cred, p)
  829         register struct pshmnode *pnode;
  830         int flags;
  831         struct ucred *cred;
  832         struct proc *p;
  833 {
  834         int error=0;
  835         kern_return_t kret;
  836         register struct pshminfo *pinfo;
  837 
  838         if ((pinfo = pnode->pinfo) == PSHMINFO_NULL)
  839                 return(EINVAL);
  840 
  841         if ((pinfo->pshm_flags & PSHM_ALLOCATED) != PSHM_ALLOCATED) {
  842                 return(EINVAL);
  843         }
  844 #if DIAGNOSTIC
  845         if(!pinfo->pshm_usecount) {
  846                 kprintf("negative usecount in pshm_close\n");
  847         }
  848 #endif /* DIAGNOSTIC */
  849         pinfo->pshm_usecount--;
  850 
  851         if ((pinfo->pshm_flags & PSHM_REMOVED) && !pinfo->pshm_usecount) {
  852                 _FREE(pinfo,M_SHM);
  853         }
  854         _FREE(pnode, M_SHM);
  855         return (error);
  856 }
  857 
  858 static int
  859 pshm_closefile(fp, p)
  860         struct file *fp;
  861         struct proc *p;
  862 {
  863         return (pshm_close(((struct pshmnode *)fp->f_data), fp->f_flag,
  864                 fp->f_cred, p));
  865 }
  866 
  867 static int
  868 pshm_read(fp, uio, cred, flags, p)
  869         struct file *fp;
  870         struct uio *uio;
  871         struct ucred *cred;
  872         int flags;
  873         struct proc *p;
  874 {
  875         return(EOPNOTSUPP);
  876 }
  877 
  878 static int
  879 pshm_write(fp, uio, cred, flags, p)
  880         struct file *fp;
  881         struct uio *uio;
  882         struct ucred *cred;
  883         int flags;
  884         struct proc *p;
  885 {
  886         return(EOPNOTSUPP);
  887 }
  888 
  889 static int
  890 pshm_ioctl(fp, com, data, p)
  891         struct file *fp;
  892         u_long com;
  893         caddr_t data;
  894         struct proc *p;
  895 {
  896         return(EOPNOTSUPP);
  897 }
  898 
  899 static int
  900 pshm_select(fp, which, wql, p)
  901         struct file *fp;
  902         int which;
  903         void *wql;
  904         struct proc *p;
  905 {
  906         return(EOPNOTSUPP);
  907 }
  908 
  909 static int
  910 pshm_kqfilter(fp, kn, p)
  911         struct file *fp;
  912         struct knote *kn;
  913         struct proc *p;
  914 {
  915         return(EOPNOTSUPP);
  916 }

Cache object: 0ac2abc9da3f056fb14f143a6f4e451c


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