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