]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/posix_shm.c
xnu-344.2.tar.gz
[apple/xnu.git] / bsd / kern / posix_shm.c
1 /*
2 * Copyright (c) 2000-2002 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
64 struct 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
90 struct 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
98 struct 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
107 struct 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
113 struct 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])
128 LIST_HEAD(pshmhashhead, pshmcache) *pshmhashtbl; /* Hash Table */
129 u_long pshmhash; /* size of hash table - 1 */
130 long pshmnument; /* number of cache entries allocated */
131 struct pshmstats pshmstats; /* cache effectiveness statistics */
132
133 static int pshm_read __P((struct file *fp, struct uio *uio,
134 struct ucred *cred, int flags, struct proc *p));
135 static int pshm_write __P((struct file *fp, struct uio *uio,
136 struct ucred *cred, int flags, struct proc *p));
137 static int pshm_ioctl __P((struct file *fp, u_long com,
138 caddr_t data, struct proc *p));
139 static int pshm_select __P((struct file *fp, int which, void *wql,
140 struct proc *p));
141 static int pshm_closefile __P((struct file *fp, struct proc *p));
142
143 struct fileops pshmops =
144 { pshm_read, pshm_write, pshm_ioctl, pshm_select, pshm_closefile };
145
146 /*
147 * Lookup an entry in the cache
148 *
149 *
150 * status of -1 is returned if matches
151 * If the lookup determines that the name does not exist
152 * (negative cacheing), a status of ENOENT is returned. If the lookup
153 * fails, a status of zero is returned.
154 */
155
156 int
157 pshm_cache_search(pshmp, pnp, pcache)
158 struct pshminfo **pshmp;
159 struct pshmname *pnp;
160 struct pshmcache **pcache;
161 {
162 register struct pshmcache *pcp, *nnp;
163 register struct pshmhashhead *pcpp;
164
165 if (pnp->pshm_namelen > PSHMNAMLEN) {
166 pshmstats.longnames++;
167 return (0);
168 }
169
170 pcpp = PSHMHASH(pnp);
171 for (pcp = pcpp->lh_first; pcp != 0; pcp = nnp) {
172 nnp = pcp->pshm_hash.le_next;
173 if (pcp->pshm_nlen == pnp->pshm_namelen &&
174 !bcmp(pcp->pshm_name, pnp->pshm_nameptr, (u_int)pcp-> pshm_nlen))
175 break;
176 }
177
178 if (pcp == 0) {
179 pshmstats.miss++;
180 return (0);
181 }
182
183 /* We found a "positive" match, return the vnode */
184 if (pcp->pshminfo) {
185 pshmstats.goodhits++;
186 /* TOUCH(ncp); */
187 *pshmp = pcp->pshminfo;
188 *pcache = pcp;
189 return (-1);
190 }
191
192 /*
193 * We found a "negative" match, ENOENT notifies client of this match.
194 * The nc_vpid field records whether this is a whiteout.
195 */
196 pshmstats.neghits++;
197 return (ENOENT);
198 }
199
200 /*
201 * Add an entry to the cache.
202 */
203 int
204 pshm_cache_add(pshmp, pnp)
205 struct pshminfo *pshmp;
206 struct pshmname *pnp;
207 {
208 register struct pshmcache *pcp;
209 register struct pshmhashhead *pcpp;
210 register struct pshminfo *dpinfo;
211 register struct pshmcache *dpcp;
212
213 #if DIAGNOSTIC
214 if (pnp->pshm_namelen > NCHNAMLEN)
215 panic("cache_enter: name too long");
216 #endif
217
218 /*
219 * We allocate a new entry if we are less than the maximum
220 * allowed and the one at the front of the LRU list is in use.
221 * Otherwise we use the one at the front of the LRU list.
222 */
223 pcp = (struct pshmcache *)_MALLOC(sizeof(struct pshmcache), M_SHM, M_WAITOK);
224 /* if the entry has already been added by some one else return */
225 if (pshm_cache_search(&dpinfo, pnp, &dpcp) == -1) {
226 _FREE(pcp, M_SHM);
227 return(EEXIST);
228 }
229 pshmnument++;
230
231 bzero(pcp, sizeof(struct pshmcache));
232 /*
233 * Fill in cache info, if vp is NULL this is a "negative" cache entry.
234 * For negative entries, we have to record whether it is a whiteout.
235 * the whiteout flag is stored in the nc_vpid field which is
236 * otherwise unused.
237 */
238 pcp->pshminfo = pshmp;
239 pcp->pshm_nlen = pnp->pshm_namelen;
240 bcopy(pnp->pshm_nameptr, pcp->pshm_name, (unsigned)pcp->pshm_nlen);
241 pcpp = PSHMHASH(pnp);
242 #if DIAGNOSTIC
243 {
244 register struct pshmcache *p;
245
246 for (p = pcpp->lh_first; p != 0; p = p->pshm_hash.le_next)
247 if (p == pcp)
248 panic("cache_enter: duplicate");
249 }
250 #endif
251 LIST_INSERT_HEAD(pcpp, pcp, pshm_hash);
252 return(0);
253 }
254
255 /*
256 * Name cache initialization, from vfs_init() when we are booting
257 */
258 void
259 pshm_cache_init()
260 {
261 pshmhashtbl = hashinit(desiredvnodes, M_SHM, &pshmhash);
262 }
263
264 /*
265 * Invalidate a all entries to particular vnode.
266 *
267 * We actually just increment the v_id, that will do it. The entries will
268 * be purged by lookup as they get found. If the v_id wraps around, we
269 * need to ditch the entire cache, to avoid confusion. No valid vnode will
270 * ever have (v_id == 0).
271 */
272 void
273 pshm_cache_purge(void)
274 {
275 struct pshmcache *pcp;
276 struct pshmhashhead *pcpp;
277
278 for (pcpp = &pshmhashtbl[pshmhash]; pcpp >= pshmhashtbl; pcpp--) {
279 while (pcp = pcpp->lh_first)
280 pshm_cache_delete(pcp);
281 }
282 }
283
284 pshm_cache_delete(pcp)
285 struct pshmcache *pcp;
286 {
287 #if DIAGNOSTIC
288 if (pcp->pshm_hash.le_prev == 0)
289 panic("namecache purge le_prev");
290 if (pcp->pshm_hash.le_next == pcp)
291 panic("namecache purge le_next");
292 #endif /* DIAGNOSTIC */
293 LIST_REMOVE(pcp, pshm_hash);
294 pcp->pshm_hash.le_prev = 0;
295 pshmnument--;
296 }
297
298
299 struct shm_open_args {
300 const char *name;
301 int oflag;
302 int mode;
303 };
304
305 int
306 shm_open(p, uap, retval)
307 struct proc *p;
308 register struct shm_open_args *uap;
309 register_t *retval;
310 {
311 register struct filedesc *fdp = p->p_fd;
312 register struct file *fp;
313 register struct vnode *vp;
314 int i;
315 struct file *nfp;
316 int type, indx, error;
317 struct pshmname nd;
318 struct pshminfo *pinfo;
319 extern struct fileops pshmops;
320 char * pnbuf;
321 char * nameptr;
322 char * cp;
323 size_t pathlen, plen;
324 int fmode ;
325 int cmode = uap->mode;
326 int incache = 0;
327 struct pshmnode * pnode = PSHMNODE_NULL;
328 struct pshmcache * pcache = PSHMCACHE_NULL;
329 int pinfo_alloc=0;
330
331
332 pinfo = PSHMINFO_NULL;
333
334 MALLOC_ZONE(pnbuf, caddr_t,
335 MAXPATHLEN, M_NAMEI, M_WAITOK);
336 pathlen = MAXPATHLEN;
337 error = copyinstr(uap->name, pnbuf,
338 MAXPATHLEN, &pathlen);
339 if (error) {
340 goto bad;
341 }
342 if (pathlen > PSHMNAMLEN) {
343 error = ENAMETOOLONG;
344 goto bad;
345 }
346
347
348 #ifdef PSXSHM_NAME_RESTRICT
349 nameptr = pnbuf;
350 if (*nameptr == '/') {
351 while (*(nameptr++) == '/') {
352 plen--;
353 error = EINVAL;
354 goto bad;
355 }
356 } else {
357 error = EINVAL;
358 goto bad;
359 }
360 #endif /* PSXSHM_NAME_RESTRICT */
361
362 plen = pathlen;
363 nameptr = pnbuf;
364 nd.pshm_nameptr = nameptr;
365 nd.pshm_namelen = plen;
366 nd. pshm_hash =0;
367
368 for (cp = nameptr, i=1; *cp != 0 && i <= plen; i++, cp++) {
369 nd.pshm_hash += (unsigned char)*cp * i;
370 }
371
372 error = pshm_cache_search(&pinfo, &nd, &pcache);
373
374 if (error == ENOENT) {
375 error = EINVAL;
376 goto bad;
377
378 }
379 if (!error) {
380 incache = 0;
381 } else
382 incache = 1;
383 fmode = FFLAGS(uap->oflag);
384 if ((fmode & (FREAD | FWRITE))==0)
385 return(EINVAL);
386
387 if (error = falloc(p, &nfp, &indx))
388 return (error);
389 fp = nfp;
390
391 cmode &= ALLPERMS;
392
393 if (fmode & O_CREAT) {
394 if ((fmode & O_EXCL) && incache) {
395 /* shm obj exists and opened O_EXCL */
396 #if notyet
397 if (pinfo->pshm_flags & PSHM_INDELETE) {
398 }
399 #endif
400 error = EEXIST;
401 goto bad1;
402 }
403 if (!incache) {
404 /* create a new one */
405 pinfo = (struct pshminfo *)_MALLOC(sizeof(struct pshminfo), M_SHM, M_WAITOK);
406 bzero(pinfo, sizeof(struct pshminfo));
407 pinfo_alloc = 1;
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 bad1;
418 }
419 if (error = pshm_access(pinfo, fmode, p->p_ucred, p))
420 goto bad1;
421 }
422 } else {
423 if (!incache) {
424 /* O_CREAT is not set and the shm obecj does not exist */
425 error = ENOENT;
426 goto bad1;
427 }
428 if( pinfo->pshm_flags & PSHM_INDELETE) {
429 error = ENOENT;
430 goto bad1;
431 }
432 if (error = pshm_access(pinfo, fmode, p->p_ucred, p))
433 goto bad1;
434 }
435 if (fmode & O_TRUNC) {
436 error = EINVAL;
437 goto bad2;
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 bad3;
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);
464 bad3:
465 _FREE(pnode, M_SHM);
466
467 bad2:
468 if (pinfo_alloc)
469 _FREE(pinfo, M_SHM);
470 bad1:
471 fdrelse(p, indx);
472 ffree(nfp);
473 bad:
474 _FREE_ZONE(pnbuf, MAXPATHLEN, M_NAMEI);
475 return (error);
476 }
477
478
479 /* ARGSUSED */
480 int
481 pshm_truncate(p, fp, fd, length, retval)
482 struct proc *p;
483 struct file *fp;
484 int fd;
485 off_t length;
486 register_t *retval;
487 {
488 struct pshminfo * pinfo;
489 struct pshmnode * pnode ;
490 kern_return_t kret;
491 vm_offset_t user_addr;
492 void * mem_object;
493 vm_size_t size;
494
495 if (fp->f_type != DTYPE_PSXSHM) {
496 return(EINVAL);
497 }
498
499
500 if (((pnode = (struct pshmnode *)fp->f_data)) == PSHMNODE_NULL )
501 return(EINVAL);
502
503 if ((pinfo = pnode->pinfo) == PSHMINFO_NULL)
504 return(EINVAL);
505 if ((pinfo->pshm_flags & (PSHM_DEFINED | PSHM_ALLOCATED))
506 != PSHM_DEFINED) {
507 return(EINVAL);
508 }
509
510 size = round_page (length);
511 kret = vm_allocate(current_map(), &user_addr, size, TRUE);
512 if (kret != KERN_SUCCESS)
513 goto out;
514
515 kret = mach_make_memory_entry (current_map(), &size,
516 user_addr, VM_PROT_DEFAULT, &mem_object, 0);
517
518 if (kret != KERN_SUCCESS)
519 goto out;
520
521 vm_deallocate(current_map(), user_addr, size);
522
523 pinfo->pshm_flags &= ~PSHM_DEFINED;
524 pinfo->pshm_flags = PSHM_ALLOCATED;
525 pinfo->pshm_memobject = mem_object;
526 pinfo->pshm_length = size;
527 return(0);
528
529 out:
530 switch (kret) {
531 case KERN_INVALID_ADDRESS:
532 case KERN_NO_SPACE:
533 return (ENOMEM);
534 case KERN_PROTECTION_FAILURE:
535 return (EACCES);
536 default:
537 return (EINVAL);
538
539 }
540 }
541
542 int
543 pshm_stat(pnode, sb)
544 struct pshmnode *pnode;
545 struct stat *sb;
546 {
547 struct pshminfo *pinfo;
548
549 if ((pinfo = pnode->pinfo) == PSHMINFO_NULL)
550 return(EINVAL);
551
552 bzero(sb, sizeof(struct stat));
553 sb->st_mode = pinfo->pshm_mode;
554 sb->st_uid = pinfo->pshm_uid;
555 sb->st_gid = pinfo->pshm_gid;
556 sb->st_size = pinfo->pshm_length;
557
558 return(0);
559 }
560
561 int
562 pshm_access(struct pshminfo *pinfo, int mode, struct ucred *cred, struct proc *p)
563 {
564 mode_t mask;
565 register gid_t *gp;
566 int i, error;
567
568 /* Otherwise, user id 0 always gets access. */
569 if (cred->cr_uid == 0)
570 return (0);
571
572 mask = 0;
573
574 /* Otherwise, check the owner. */
575 if (cred->cr_uid == pinfo->pshm_uid) {
576 if (mode & FREAD)
577 mask |= S_IRUSR;
578 if (mode & FWRITE)
579 mask |= S_IWUSR;
580 return ((pinfo->pshm_mode & mask) == mask ? 0 : EACCES);
581 }
582
583 /* Otherwise, check the groups. */
584 for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++)
585 if (pinfo->pshm_gid == *gp) {
586 if (mode & FREAD)
587 mask |= S_IRGRP;
588 if (mode & FWRITE)
589 mask |= S_IWGRP;
590 return ((pinfo->pshm_mode & mask) == mask ? 0 : EACCES);
591 }
592
593 /* Otherwise, check everyone else. */
594 if (mode & FREAD)
595 mask |= S_IROTH;
596 if (mode & FWRITE)
597 mask |= S_IWOTH;
598 return ((pinfo->pshm_mode & mask) == mask ? 0 : EACCES);
599 }
600
601 struct mmap_args {
602 caddr_t addr;
603 size_t len;
604 int prot;
605 int flags;
606 int fd;
607 #ifdef DOUBLE_ALIGN_PARAMS
608 long pad;
609 #endif
610 off_t pos;
611 };
612
613 int
614 pshm_mmap(struct proc *p, struct mmap_args *uap, register_t *retval, struct file *fp, vm_size_t pageoff)
615 {
616 vm_offset_t user_addr = uap->addr;
617 vm_size_t user_size = uap->len ;
618 int prot = uap->prot;
619 int flags = uap->flags;
620 vm_object_offset_t file_pos = (vm_object_offset_t)uap->pos;
621 int fd = uap->fd;
622 vm_map_t user_map;
623 boolean_t find_space,docow;
624 kern_return_t kret;
625 struct pshminfo * pinfo;
626 struct pshmnode * pnode;
627 void * mem_object;
628
629 if (user_size == 0)
630 return(0);
631
632 if ((flags & MAP_SHARED) == 0)
633 return(EINVAL);
634
635
636 if ((prot & PROT_WRITE) && ((fp->f_flag & FWRITE) == 0)) {
637 return(EPERM);
638 }
639
640 if (((pnode = (struct pshmnode *)fp->f_data)) == PSHMNODE_NULL )
641 return(EINVAL);
642
643 if ((pinfo = pnode->pinfo) == PSHMINFO_NULL)
644 return(EINVAL);
645
646 if ((pinfo->pshm_flags & PSHM_ALLOCATED) != PSHM_ALLOCATED) {
647 return(EINVAL);
648 }
649 if (user_size > pinfo->pshm_length) {
650 return(EINVAL);
651 }
652 if ((off_t)user_size + file_pos > pinfo->pshm_length) {
653 return(EINVAL);
654 }
655 if ((mem_object = pinfo->pshm_memobject) == NULL) {
656 return(EINVAL);
657 }
658
659
660 user_map = current_map();
661
662 if ((flags & MAP_FIXED) == 0) {
663 find_space = TRUE;
664 user_addr = round_page(user_addr);
665 } else {
666 if (user_addr != trunc_page(user_addr))
667 return (EINVAL);
668 find_space = FALSE;
669 (void) vm_deallocate(user_map, user_addr, user_size);
670 }
671 docow = FALSE;
672
673 kret = vm_map_64(user_map, &user_addr, user_size,
674 0, find_space, pinfo->pshm_memobject, file_pos, docow,
675 prot, VM_PROT_DEFAULT,
676 VM_INHERIT_DEFAULT);
677
678 if (kret != KERN_SUCCESS)
679 goto out;
680 kret = vm_inherit(user_map, user_addr, user_size,
681 VM_INHERIT_SHARE);
682 if (kret != KERN_SUCCESS) {
683 (void) vm_deallocate(user_map, user_addr, user_size);
684 goto out;
685 }
686 pnode->mapp_addr = user_addr;
687 pnode->map_size = user_size;
688 pinfo->pshm_flags |= (PSHM_MAPPED | PSHM_INUSE);
689 out:
690 switch (kret) {
691 case KERN_SUCCESS:
692 *fdflags(p, fd) |= UF_MAPPED;
693 *retval = (register_t)(user_addr + pageoff);
694 return (0);
695 case KERN_INVALID_ADDRESS:
696 case KERN_NO_SPACE:
697 return (ENOMEM);
698 case KERN_PROTECTION_FAILURE:
699 return (EACCES);
700 default:
701 return (EINVAL);
702 }
703
704 }
705
706 struct shm_unlink_args {
707 const char *name;
708 };
709
710 int
711 shm_unlink(p, uap, retval)
712 struct proc *p;
713 register struct shm_unlink_args *uap;
714 register_t *retval;
715 {
716 register struct filedesc *fdp = p->p_fd;
717 register struct file *fp;
718 int flags, i;
719 int error=0;
720 struct pshmname nd;
721 struct pshminfo *pinfo;
722 extern struct fileops pshmops;
723 char * pnbuf;
724 char * nameptr;
725 char * cp;
726 size_t pathlen, plen;
727 int fmode, cmode ;
728 int incache = 0;
729 struct pshmnode * pnode = PSHMNODE_NULL;
730 struct pshmcache *pcache = PSHMCACHE_NULL;
731 kern_return_t kret;
732
733 pinfo = PSHMINFO_NULL;
734
735 MALLOC_ZONE(pnbuf, caddr_t,
736 MAXPATHLEN, M_NAMEI, M_WAITOK);
737 pathlen = MAXPATHLEN;
738 error = copyinstr(uap->name, pnbuf,
739 MAXPATHLEN, &pathlen);
740 if (error) {
741 goto bad;
742 }
743 if (pathlen > PSHMNAMLEN) {
744 error = ENAMETOOLONG;
745 goto bad;
746 }
747
748
749 #ifdef PSXSHM_NAME_RESTRICT
750 nameptr = pnbuf;
751 if (*nameptr == '/') {
752 while (*(nameptr++) == '/') {
753 plen--;
754 error = EINVAL;
755 goto bad;
756 }
757 } else {
758 error = EINVAL;
759 goto bad;
760 }
761 #endif /* PSXSHM_NAME_RESTRICT */
762
763 plen = pathlen;
764 nameptr = pnbuf;
765 nd.pshm_nameptr = nameptr;
766 nd.pshm_namelen = plen;
767 nd. pshm_hash =0;
768
769 for (cp = nameptr, i=1; *cp != 0 && i <= plen; i++, cp++) {
770 nd.pshm_hash += (unsigned char)*cp * i;
771 }
772
773 error = pshm_cache_search(&pinfo, &nd, &pcache);
774
775 if (error == ENOENT) {
776 error = EINVAL;
777 goto bad;
778
779 }
780 if (!error) {
781 error = EINVAL;
782 goto bad;
783 } else
784 incache = 1;
785
786 if ((pinfo->pshm_flags & (PSHM_DEFINED | PSHM_ALLOCATED))==0) {
787 return (EINVAL);
788 }
789
790 if (pinfo->pshm_flags & PSHM_INDELETE) {
791 error = 0;
792 goto bad;
793 }
794
795 if (pinfo->pshm_memobject == NULL) {
796 error = EINVAL;
797 goto bad;
798 }
799
800 pinfo->pshm_flags |= PSHM_INDELETE;
801 pinfo->pshm_usecount--;
802 kret = mach_destroy_memory_entry(pinfo->pshm_memobject);
803 pshm_cache_delete(pcache);
804 _FREE(pcache, M_SHM);
805 pinfo->pshm_flags |= PSHM_REMOVED;
806 error = 0;
807 bad:
808 _FREE_ZONE(pnbuf, MAXPATHLEN, M_NAMEI);
809 return (error);
810 out:
811 switch (kret) {
812 case KERN_INVALID_ADDRESS:
813 case KERN_PROTECTION_FAILURE:
814 return (EACCES);
815 default:
816 return (EINVAL);
817 }
818 }
819
820 int
821 pshm_close(pnode, flags, cred, p)
822 register struct pshmnode *pnode;
823 int flags;
824 struct ucred *cred;
825 struct proc *p;
826 {
827 int error=0;
828 kern_return_t kret;
829 register struct pshminfo *pinfo;
830
831 if ((pinfo = pnode->pinfo) == PSHMINFO_NULL)
832 return(EINVAL);
833
834 if ((pinfo->pshm_flags & PSHM_ALLOCATED) != PSHM_ALLOCATED) {
835 return(EINVAL);
836 }
837 #if DIAGNOSTIC
838 if(!pinfo->pshm_usecount) {
839 kprintf("negative usecount in pshm_close\n");
840 }
841 #endif /* DIAGNOSTIC */
842 pinfo->pshm_usecount--;
843
844 if ((pinfo->pshm_flags & PSHM_REMOVED) && !pinfo->pshm_usecount) {
845 _FREE(pinfo,M_SHM);
846 }
847 _FREE(pnode, M_SHM);
848 return (error);
849 }
850
851 static int
852 pshm_closefile(fp, p)
853 struct file *fp;
854 struct proc *p;
855 {
856 return (pshm_close(((struct pshmnode *)fp->f_data), fp->f_flag,
857 fp->f_cred, p));
858 }
859
860 static int
861 pshm_read(fp, uio, cred, flags, p)
862 struct file *fp;
863 struct uio *uio;
864 struct ucred *cred;
865 int flags;
866 struct proc *p;
867 {
868 return(EOPNOTSUPP);
869 }
870
871 static int
872 pshm_write(fp, uio, cred, flags, p)
873 struct file *fp;
874 struct uio *uio;
875 struct ucred *cred;
876 int flags;
877 struct proc *p;
878 {
879 return(EOPNOTSUPP);
880 }
881
882 static int
883 pshm_ioctl(fp, com, data, p)
884 struct file *fp;
885 u_long com;
886 caddr_t data;
887 struct proc *p;
888 {
889 return(EOPNOTSUPP);
890 }
891
892 static int
893 pshm_select(fp, which, wql, p)
894 struct file *fp;
895 int which;
896 void *wql;
897 struct proc *p;
898 {
899 return(EOPNOTSUPP);
900 }