int sys_shmget(struct proc *p, void *v, register_t *retval) { struct sys_shmget_args /* { syscallarg(key_t) key; syscallarg(size_t) size; syscallarg(int) shmflg; } */ *uap = v; int segnum, mode, error; mode = SCARG(uap, shmflg) & ACCESSPERMS; if (SCARG(uap, key) != IPC_PRIVATE) { again: segnum = shm_find_segment_by_key(SCARG(uap, key)); if (segnum >= 0) return (shmget_existing(p, uap, mode, segnum, retval)); if ((SCARG(uap, shmflg) & IPC_CREAT) == 0) return (ENOENT); } error = shmget_allocate_segment(p, uap, mode, retval); if (error == EAGAIN) goto again; return (error); }
/* Handle a shmget() request. */ int handle_shmget(pid_t pid, struct shmget_msg *shmget_msg, struct cmsgcred *cred ) { int segnum, mode, error; struct shmid_ds *shmseg; struct shm_handle *handle; //if (!jail_sysvipc_allowed && td->td_cmsgcred->cr_prison != NULL) // return (ENOSYS); mode = shmget_msg->shmflg & ACCESSPERMS; sysvd_print("ask for key = %ld\n", shmget_msg->key); shmget_msg->key = (shmget_msg->key & 0x3FFF) | (shmget_msg->type << 30); sysvd_print("ask for key = %ld\n", shmget_msg->key); if (shmget_msg->key != IPC_PRIVATE) { //again: segnum = shm_find_segment_by_key(shmget_msg->key); if (segnum >= 0) { error = shmget_existing(shmget_msg, mode, segnum, cred); //TODO if daemon is multithreading //if (error == EAGAIN) // goto again; goto done; } if ((shmget_msg->shmflg & IPC_CREAT) == 0) { error = -ENOENT; goto done_err; } } error = shmget_allocate_segment(pid, shmget_msg, mode, cred); sysvd_print("allocate segment = %d\n", error); done: /* * Install to th client the file corresponding to the * shared memory segment. * client_fd is the file descriptor added in the client * files table. */ shmseg = shm_find_segment_by_shmid(error); if (shmseg == NULL) { sysvd_print_err("can not find segment by shmid\n"); return (-1); } handle = (struct shm_handle *)shmseg->shm_internal; if (install_fd_client(pid, handle->fd) != 0) error = errno; done_err: return (error); }
int shmget_allocate_segment(struct proc *p, struct sys_shmget_args /* { syscallarg(key_t) key; syscallarg(size_t) size; syscallarg(int) shmflg; } */ *uap, int mode, register_t *retval) { size_t size; key_t key; int segnum; struct ucred *cred = p->p_ucred; struct shmid_ds *shmseg; struct shm_handle *shm_handle; int error = 0; if (SCARG(uap, size) < shminfo.shmmin || SCARG(uap, size) > shminfo.shmmax) return (EINVAL); if (shm_nused >= shminfo.shmmni) /* any shmids left? */ return (ENOSPC); size = round_page(SCARG(uap, size)); if (shm_committed + atop(size) > shminfo.shmall) return (ENOMEM); shm_nused++; shm_committed += atop(size); /* * If a key has been specified and we had to wait for memory * to be freed up we need to verify that no one has allocated * the key we want in the meantime. Yes, this is ugly. */ key = SCARG(uap, key); shmseg = pool_get(&shm_pool, key == IPC_PRIVATE ? PR_WAITOK : PR_NOWAIT); if (shmseg == NULL) { shmseg = pool_get(&shm_pool, PR_WAITOK); if (shm_find_segment_by_key(key) != -1) { pool_put(&shm_pool, shmseg); shm_nused--; shm_committed -= atop(size); return (EAGAIN); } } /* XXX - hash shmids instead */ if (shm_last_free < 0) { for (segnum = 0; segnum < shminfo.shmmni && shmsegs[segnum]; segnum++) ; if (segnum == shminfo.shmmni) panic("shmseg free count inconsistent"); } else { segnum = shm_last_free; if (++shm_last_free >= shminfo.shmmni || shmsegs[shm_last_free]) shm_last_free = -1; } shmsegs[segnum] = shmseg; shm_handle = (struct shm_handle *)((caddr_t)shmseg + sizeof(*shmseg)); shm_handle->shm_object = uao_create(size, 0); shmseg->shm_perm.cuid = shmseg->shm_perm.uid = cred->cr_uid; shmseg->shm_perm.cgid = shmseg->shm_perm.gid = cred->cr_gid; shmseg->shm_perm.mode = (mode & ACCESSPERMS); shmseg->shm_perm.seq = shmseqs[segnum] = (shmseqs[segnum] + 1) & 0x7fff; shmseg->shm_perm.key = key; shmseg->shm_segsz = SCARG(uap, size); shmseg->shm_cpid = p->p_p->ps_pid; shmseg->shm_lpid = shmseg->shm_nattch = 0; shmseg->shm_atime = shmseg->shm_dtime = 0; shmseg->shm_ctime = time_second; shmseg->shm_internal = shm_handle; *retval = IXSEQ_TO_IPCID(segnum, shmseg->shm_perm); return (error); }