--- /usr/src/sys/kern/sysv_shm.c Sun Mar 25 03:26:07 2007 +++ s Mon Apr 30 15:23:49 2007 @@ -1,3 +1,4 @@ +//depot/user/wkoszek/wkoszek_lessgiant/src/sys/kern/sysv_shm.c#3 - edit change 116478 (text+ko) /* $NetBSD: sysv_shm.c,v 1.23 1994/07/04 23:25:12 glass Exp $ */ /*- * Copyright (c) 1994 Adam Glass and Charles Hannum. All rights reserved. @@ -72,6 +73,7 @@ #include #include #include +#include #include #include #include @@ -123,6 +125,24 @@ static int shm_last_free, shm_nused, shm_committed, shmalloced; static struct shmid_kernel *shmsegs; +static struct sx shm_sx; + +#define SHM_SX_XLOCK() sx_xlock(&(shm_sx)) +#define SHM_SX_XUNLOCK() sx_xunlock(&(shm_sx)) +#define SHM_SX_LOCK_INIT() sx_init(&(shm_sx), "shm_mtx"); +#define SHM_SX_LOCK_DESTROY() sx_destroy(&(shm_sx)) +#define SHM_SX_ASSERT(f) sx_assert(&(shm_sx), (f)) + +static u_int shm_debug = 0; + +#define SHM_DEBUG(...) do { \ + if (shm_debug == 1) { \ + printf("%s(%d)", __func__, __LINE__); \ + printf(__VA_ARGS__); \ + printf("\n"); \ + } \ +} while (0) + struct shmmap_state { vm_offset_t va; @@ -134,7 +154,6 @@ static struct shmid_kernel *shm_find_segment_by_shmid(int); static struct shmid_kernel *shm_find_segment_by_shmidx(int); static int shm_delete_mapping(struct vmspace *vm, struct shmmap_state *); -static void shmrealloc(void); static void shminit(void); static int sysvshm_modload(struct module *, int, void *); static int shmunload(void); @@ -195,15 +214,17 @@ "Current number of shared memory segments allocated"); static int -shm_find_segment_by_key(key) - key_t key; +shm_find_segment_by_key(key_t key) { + struct ipc_perm *pm; int i; - for (i = 0; i < shmalloced; i++) - if ((shmsegs[i].u.shm_perm.mode & SHMSEG_ALLOCATED) && - shmsegs[i].u.shm_perm.key == key) + SHM_SX_ASSERT(SX_LOCKED); + for (i = 0; i < shmalloced; i++) { + pm = &(shmsegs[i].u.shm_perm); + if (pm->mode & SHMSEG_ALLOCATED && pm->key == key) return (i); + } return (-1); } @@ -213,15 +234,27 @@ int segnum; struct shmid_kernel *shmseg; + SHM_SX_ASSERT(SX_LOCKED); + segnum = IPCID_TO_IX(shmid); - if (segnum < 0 || segnum >= shmalloced) + if (segnum < 0 || segnum >= shmalloced) { + SHM_DEBUG("segnum improper"); return (NULL); + } shmseg = &shmsegs[segnum]; - if ((shmseg->u.shm_perm.mode & SHMSEG_ALLOCATED) == 0 || - (!shm_allow_removed && - (shmseg->u.shm_perm.mode & SHMSEG_REMOVED) != 0) || - shmseg->u.shm_perm.seq != IPCID_TO_SEQ(shmid)) + if ((shmseg->u.shm_perm.mode & SHMSEG_ALLOCATED) == 0) { + SHM_DEBUG("not allocated"); return (NULL); + } + if (!shm_allow_removed && + (shmseg->u.shm_perm.mode & SHMSEG_REMOVED) != 0) { + SHM_DEBUG("shseg_removed"); + return (NULL); + } + if (shmseg->u.shm_perm.seq != IPCID_TO_SEQ(shmid)) { + SHM_DEBUG("shmseg == NULL"); + return (NULL); + } return (shmseg); } @@ -229,14 +262,24 @@ shm_find_segment_by_shmidx(int segnum) { struct shmid_kernel *shmseg; + struct ipc_perm *pm; + + SHM_SX_ASSERT(SX_LOCKED); - if (segnum < 0 || segnum >= shmalloced) + if (segnum < 0 || segnum >= shmalloced) { + SHM_DEBUG("segnum improper"); return (NULL); + } shmseg = &shmsegs[segnum]; - if ((shmseg->u.shm_perm.mode & SHMSEG_ALLOCATED) == 0 || - (!shm_allow_removed && - (shmseg->u.shm_perm.mode & SHMSEG_REMOVED) != 0)) + pm = &(shmseg->u.shm_perm); + if ((pm->mode & SHMSEG_ALLOCATED) == 0) { + SHM_DEBUG("segnum improper"); + return (NULL); + } + if (!shm_allow_removed && (pm->mode & SHMSEG_REMOVED) != 0) { + SHM_DEBUG("segnum improper"); return (NULL); + } return (shmseg); } @@ -246,7 +289,7 @@ { size_t size; - GIANT_REQUIRED; + SHM_SX_ASSERT(SX_XLOCKED); vm_object_deallocate(shmseg->u.shm_internal); shmseg->u.shm_internal = NULL; @@ -266,7 +309,7 @@ int segnum, result; size_t size; - GIANT_REQUIRED; + SHM_SX_ASSERT(SX_XLOCKED); segnum = IPCID_TO_IX(shmmap_s->shmid); shmseg = &shmsegs[segnum]; @@ -304,12 +347,10 @@ if (!jail_sysvipc_allowed && jailed(td->td_ucred)) return (ENOSYS); - mtx_lock(&Giant); shmmap_s = p->p_vmspace->vm_shm; - if (shmmap_s == NULL) { - error = EINVAL; - goto done2; - } + if (shmmap_s == NULL) + return (EINVAL); + SHM_SX_XLOCK(); for (i = 0; i < shminfo.shmseg; i++, shmmap_s++) { if (shmmap_s->shmid != -1 && shmmap_s->va == (vm_offset_t)uap->shmaddr) { @@ -317,18 +358,21 @@ } } if (i == shminfo.shmseg) { - error = EINVAL; - goto done2; + SHM_SX_XUNLOCK(); + return (EINVAL); } #ifdef MAC shmsegptr = &shmsegs[IPCID_TO_IX(shmmap_s->shmid)]; error = mac_check_sysv_shmdt(td->td_ucred, shmsegptr); - if (error != 0) - goto done2; + if (error != 0) { + SHM_SX_XUNLOCK(); + SHM_DEBUG("error = %d\n", error); + return (error); + } #endif error = shm_delete_mapping(p->p_vmspace, shmmap_s); -done2: - mtx_unlock(&Giant); + SHM_SX_XUNLOCK(); + SHM_DEBUG("error = %d\n", error); return (error); } @@ -358,15 +402,17 @@ if (!jail_sysvipc_allowed && jailed(td->td_ucred)) return (ENOSYS); - mtx_lock(&Giant); - shmmap_s = p->p_vmspace->vm_shm; - if (shmmap_s == NULL) { + if (p->p_vmspace->vm_shm == NULL) { size = shminfo.shmseg * sizeof(struct shmmap_state); shmmap_s = malloc(size, M_SHM, M_WAITOK); for (i = 0; i < shminfo.shmseg; i++) shmmap_s[i].shmid = -1; p->p_vmspace->vm_shm = shmmap_s; + } else { + shmmap_s = p->p_vmspace->vm_shm; } + SHM_SX_XLOCK(); + /* This should go first, really.. */ shmseg = shm_find_segment_by_shmid(shmid); if (shmseg == NULL) { error = EINVAL; @@ -438,7 +484,8 @@ shmseg->u.shm_nattch++; td->td_retval[0] = attach_va; done2: - mtx_unlock(&Giant); + SHM_SX_XUNLOCK(); + SHM_DEBUG("error = %d\n", error); return (error); } @@ -480,14 +527,13 @@ if (!jail_sysvipc_allowed && jailed(td->td_ucred)) return (ENOSYS); - mtx_lock(&Giant); + SHM_SX_XLOCK(); shmseg = shm_find_segment_by_shmid(uap->shmid); if (shmseg == NULL) { error = EINVAL; goto done2; } - switch (uap->cmd) { - case IPC_STAT: + if (uap->cmd == IPC_STAT) { error = ipcperm(td, &shmseg->u.shm_perm, IPC_R); if (error) goto done2; @@ -505,16 +551,20 @@ outbuf.shm_dtime = shmseg->u.shm_dtime; outbuf.shm_ctime = shmseg->u.shm_ctime; outbuf.shm_handle = shmseg->u.shm_internal; + SHM_SX_XUNLOCK(); error = copyout(&outbuf, uap->ubuf, sizeof(outbuf)); + SHM_SX_XLOCK(); if (error) goto done2; - break; - default: + } else { + SHM_SX_XUNLOCK(); error = shmctl(td, (struct shmctl_args *)uap); - break; + SHM_DEBUG("error = %d\n", error); + return (error); } done2: - mtx_unlock(&Giant); + SHM_SX_XUNLOCK(); + SHM_DEBUG("error = %d\n", error); return (error); #else return (EINVAL); @@ -539,20 +589,23 @@ { int error = 0; struct shmid_kernel *shmseg; + struct shm_info shm_info; + struct shmid_ds *shmobj; if (!jail_sysvipc_allowed && jailed(td->td_ucred)) return (ENOSYS); - - mtx_lock(&Giant); switch (cmd) { case IPC_INFO: + SHM_SX_XLOCK(); memcpy(buf, &shminfo, sizeof(shminfo)); + SHM_SX_XUNLOCK(); if (bufsz) *bufsz = sizeof(shminfo); td->td_retval[0] = shmalloced; - goto done2; - case SHM_INFO: { - struct shm_info shm_info; + return (error); + /* NOT REACHED */ + break; + case SHM_INFO: shm_info.used_ids = shm_nused; shm_info.shm_rss = 0; /*XXX where to get from ? */ shm_info.shm_tot = 0; /*XXX where to get from ? */ @@ -563,9 +616,11 @@ if (bufsz) *bufsz = sizeof(shm_info); td->td_retval[0] = shmalloced; - goto done2; - } + return (error); + /* NOT REACHED */ + break; } + SHM_SX_XLOCK(); if (cmd == SHM_STAT) shmseg = shm_find_segment_by_shmidx(shmid); else @@ -591,25 +646,25 @@ if (cmd == SHM_STAT) td->td_retval[0] = IXSEQ_TO_IPCID(shmid, shmseg->u.shm_perm); break; - case IPC_SET: { - struct shmid_ds *shmid; + case IPC_SET: - shmid = (struct shmid_ds *)buf; + shmobj = (struct shmid_ds *)buf; error = ipcperm(td, &shmseg->u.shm_perm, IPC_M); if (error) goto done2; - shmseg->u.shm_perm.uid = shmid->shm_perm.uid; - shmseg->u.shm_perm.gid = shmid->shm_perm.gid; + shmseg->u.shm_perm.uid = shmobj->shm_perm.uid; + shmseg->u.shm_perm.gid = shmobj->shm_perm.gid; shmseg->u.shm_perm.mode = (shmseg->u.shm_perm.mode & ~ACCESSPERMS) | - (shmid->shm_perm.mode & ACCESSPERMS); + (shmobj->shm_perm.mode & ACCESSPERMS); shmseg->u.shm_ctime = time_second; break; - } case IPC_RMID: error = ipcperm(td, &shmseg->u.shm_perm, IPC_M); - if (error) + if (error) { + SHM_DEBUG("returning %d\n", error); goto done2; + } shmseg->u.shm_perm.key = IPC_PRIVATE; shmseg->u.shm_perm.mode |= SHMSEG_REMOVED; if (shmseg->u.shm_nattch <= 0) { @@ -626,7 +681,8 @@ break; } done2: - mtx_unlock(&Giant); + SHM_DEBUG("error = %d\n", error); + SHM_SX_XUNLOCK(); return (error); } @@ -660,6 +716,7 @@ } done: + SHM_DEBUG("error = %d\n", error); if (error) { /* Invalidate the return value */ td->td_retval[0] = -1; @@ -683,7 +740,9 @@ int segnum; { struct shmid_kernel *shmseg; - int error; + int error = 0; + + SHM_SX_ASSERT(SX_LOCKED); shmseg = &shmsegs[segnum]; if (shmseg->u.shm_perm.mode & SHMSEG_REMOVED) { @@ -703,12 +762,16 @@ #ifdef MAC error = mac_check_sysv_shmget(td->td_ucred, shmseg, uap->shmflg); if (error != 0) - return (error); + goto done2; #endif - if (uap->size && uap->size > shmseg->u.shm_segsz) - return (EINVAL); + if (uap->size && uap->size > shmseg->u.shm_segsz) { + error = EINVAL; + goto done2; + } td->td_retval[0] = IXSEQ_TO_IPCID(segnum, shmseg->u.shm_perm); - return (0); +done2: + SHM_DEBUG("error = %d\n", error); + return (error); } static int @@ -722,7 +785,7 @@ struct shmid_kernel *shmseg; vm_object_t shm_object; - GIANT_REQUIRED; + SHM_SX_ASSERT(SX_XLOCKED); if (uap->size < shminfo.shmmin || uap->size > shminfo.shmmax) return (EINVAL); @@ -732,7 +795,6 @@ if (shm_committed + btoc(size) > shminfo.shmall) return (ENOMEM); if (shm_last_free < 0) { - shmrealloc(); /* Maybe expand the shmsegs[] array. */ for (i = 0; i < shmalloced; i++) if (shmsegs[i].u.shm_perm.mode & SHMSEG_FREE) break; @@ -745,14 +807,15 @@ } shmseg = &shmsegs[segnum]; /* - * In case we sleep in malloc(), mark the segment present but deleted - * so that noone else tries to create the same key. + * Mark the segment present but deleted so that noone else tries to + * create the same key. */ shmseg->u.shm_perm.mode = SHMSEG_ALLOCATED | SHMSEG_REMOVED; shmseg->u.shm_perm.key = uap->key; shmseg->u.shm_perm.seq = (shmseg->u.shm_perm.seq + 1) & 0x7fff; shmid = IXSEQ_TO_IPCID(segnum, shmseg->u.shm_perm); - + + SHM_SX_XUNLOCK(); /* * We make sure that we have allocated a pager before we need * to. @@ -768,7 +831,7 @@ vm_object_clear_flag(shm_object, OBJ_ONEMAPPING); vm_object_set_flag(shm_object, OBJ_NOSPLIT); VM_OBJECT_UNLOCK(shm_object); - + SHM_SX_XLOCK(); shmseg->u.shm_internal = shm_object; shmseg->u.shm_perm.cuid = shmseg->u.shm_perm.uid = cred->cr_uid; shmseg->u.shm_perm.cgid = shmseg->u.shm_perm.gid = cred->cr_gid; @@ -806,7 +869,7 @@ if (!jail_sysvipc_allowed && jailed(td->td_ucred)) return (ENOSYS); - mtx_lock(&Giant); + SHM_SX_XLOCK(); mode = uap->shmflg & ACCESSPERMS; if (uap->key != IPC_PRIVATE) { again: @@ -823,8 +886,12 @@ } } error = shmget_allocate_segment(td, uap, mode); + SHM_SX_XUNLOCK(); + SHM_DEBUG("error = %d\n", error); + return (error); done2: - mtx_unlock(&Giant); + SHM_SX_XUNLOCK(); + SHM_DEBUG("error = %d\n", error); return (error); } @@ -847,9 +914,7 @@ if (uap->which < 0 || uap->which >= sizeof(shmcalls)/sizeof(shmcalls[0])) return (EINVAL); - mtx_lock(&Giant); error = (*shmcalls[uap->which])(td, &uap->a2); - mtx_unlock(&Giant); return (error); #else return (nosys(td, NULL)); @@ -864,15 +929,15 @@ size_t size; int i; - mtx_lock(&Giant); size = shminfo.shmseg * sizeof(struct shmmap_state); shmmap_s = malloc(size, M_SHM, M_WAITOK); bcopy(p1->p_vmspace->vm_shm, shmmap_s, size); p2->p_vmspace->vm_shm = shmmap_s; + SHM_SX_XLOCK(); for (i = 0; i < shminfo.shmseg; i++, shmmap_s++) if (shmmap_s->shmid != -1) shmsegs[IPCID_TO_IX(shmmap_s->shmid)].u.shm_nattch++; - mtx_unlock(&Giant); + SHM_SX_XUNLOCK(); } static void @@ -883,43 +948,17 @@ if ((base = vm->vm_shm) != NULL) { vm->vm_shm = NULL; - mtx_lock(&Giant); + SHM_SX_XLOCK(); for (i = 0, shm = base; i < shminfo.shmseg; i++, shm++) { if (shm->shmid != -1) shm_delete_mapping(vm, shm); } - mtx_unlock(&Giant); + SHM_SX_XUNLOCK(); free(base, M_SHM); } } static void -shmrealloc(void) -{ - int i; - struct shmid_kernel *newsegs; - - if (shmalloced >= shminfo.shmmni) - return; - - newsegs = malloc(shminfo.shmmni * sizeof(*newsegs), M_SHM, M_WAITOK); - if (newsegs == NULL) - return; - for (i = 0; i < shmalloced; i++) - bcopy(&shmsegs[i], &newsegs[i], sizeof(newsegs[0])); - for (; i < shminfo.shmmni; i++) { - shmsegs[i].u.shm_perm.mode = SHMSEG_FREE; - shmsegs[i].u.shm_perm.seq = 0; -#ifdef MAC - mac_init_sysv_shm(&shmsegs[i]); -#endif - } - free(shmsegs, M_SHM); - shmsegs = newsegs; - shmalloced = shminfo.shmmni; -} - -static void shminit() { int i; @@ -935,6 +974,7 @@ TUNABLE_ULONG_FETCH("kern.ipc.shmseg", &shminfo.shmseg); TUNABLE_INT_FETCH("kern.ipc.shm_use_phys", &shm_use_phys); + SHM_SX_LOCK_INIT(); shmalloced = shminfo.shmmni; shmsegs = malloc(shmalloced * sizeof(shmsegs[0]), M_SHM, M_WAITOK); if (shmsegs == NULL) @@ -968,6 +1008,7 @@ mac_destroy_sysv_shm(&shmsegs[i]); #endif free(shmsegs, M_SHM); + SHM_SX_LOCK_DESTROY(); shmexit_hook = NULL; shmfork_hook = NULL; return (0);