]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/posix_shm.c
11c319808e5aabc6182baf579182fbf731332835
[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 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 }