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