Module Name: src Committed By: rmind Date: Sun Apr 24 20:17:53 UTC 2011
Modified Files: src/sys/kern: kern_fork.c sys_mqueue.c src/sys/sys: mqueue.h Log Message: - Move some checks into mqueue_get() and avoid some duplication. - Simplify message queue descriptor unlinking and closure operations. - Update proc_t::p_mqueue_cnt atomically. Inherit it on fork(). - Use separate allocation for the name of message queue. To generate a diff of this commit: cvs rdiff -u -r1.180 -r1.181 src/sys/kern/kern_fork.c cvs rdiff -u -r1.31 -r1.32 src/sys/kern/sys_mqueue.c cvs rdiff -u -r1.12 -r1.13 src/sys/sys/mqueue.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/kern/kern_fork.c diff -u src/sys/kern/kern_fork.c:1.180 src/sys/kern/kern_fork.c:1.181 --- src/sys/kern/kern_fork.c:1.180 Wed Mar 23 13:57:40 2011 +++ src/sys/kern/kern_fork.c Sun Apr 24 20:17:53 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: kern_fork.c,v 1.180 2011/03/23 13:57:40 joerg Exp $ */ +/* $NetBSD: kern_fork.c,v 1.181 2011/04/24 20:17:53 rmind Exp $ */ /*- * Copyright (c) 1999, 2001, 2004, 2006, 2007, 2008 The NetBSD Foundation, Inc. @@ -67,7 +67,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: kern_fork.c,v 1.180 2011/03/23 13:57:40 joerg Exp $"); +__KERNEL_RCSID(0, "$NetBSD: kern_fork.c,v 1.181 2011/04/24 20:17:53 rmind Exp $"); #include "opt_ktrace.h" @@ -349,6 +349,9 @@ else p2->p_fd = fd_copy(); + /* XXX racy */ + p2->p_mqueue_cnt = p1->p_mqueue_cnt; + if (flags & FORK_SHARECWD) cwdshare(p2); else Index: src/sys/kern/sys_mqueue.c diff -u src/sys/kern/sys_mqueue.c:1.31 src/sys/kern/sys_mqueue.c:1.32 --- src/sys/kern/sys_mqueue.c:1.31 Tue Jan 18 20:32:53 2011 +++ src/sys/kern/sys_mqueue.c Sun Apr 24 20:17:53 2011 @@ -1,7 +1,7 @@ -/* $NetBSD: sys_mqueue.c,v 1.31 2011/01/18 20:32:53 rmind Exp $ */ +/* $NetBSD: sys_mqueue.c,v 1.32 2011/04/24 20:17:53 rmind Exp $ */ /* - * Copyright (c) 2007-2009 Mindaugas Rasiukevicius <rmind at NetBSD org> + * Copyright (c) 2007-2011 Mindaugas Rasiukevicius <rmind at NetBSD org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,37 +31,30 @@ * Defined in the Base Definitions volume of IEEE Std 1003.1-2001. * * Locking - * - * Global list of message queues (mqueue_head) and proc_t::p_mqueue_cnt - * counter are protected by mqlist_mtx lock. The very message queue and - * its members are protected by mqueue::mq_mtx. - * + * + * Global list of message queues (mqueue_head) is protected by mqlist_lock. + * Each message queue and its members are protected by mqueue::mq_mtx. + * Note that proc_t::p_mqueue_cnt is updated atomically. + * * Lock order: - * mqlist_mtx -> - * mqueue::mq_mtx + * + * mqlist_lock -> + * mqueue::mq_mtx */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sys_mqueue.c,v 1.31 2011/01/18 20:32:53 rmind Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sys_mqueue.c,v 1.32 2011/04/24 20:17:53 rmind Exp $"); #include <sys/param.h> #include <sys/types.h> -#include <sys/condvar.h> -#include <sys/errno.h> -#include <sys/fcntl.h> + #include <sys/file.h> #include <sys/filedesc.h> #include <sys/kauth.h> -#include <sys/kernel.h> -#include <sys/kmem.h> #include <sys/lwp.h> #include <sys/mqueue.h> #include <sys/module.h> -#include <sys/mutex.h> -#include <sys/pool.h> #include <sys/poll.h> -#include <sys/proc.h> -#include <sys/queue.h> #include <sys/select.h> #include <sys/signal.h> #include <sys/signalvar.h> @@ -70,8 +63,6 @@ #include <sys/syscall.h> #include <sys/syscallvar.h> #include <sys/syscallargs.h> -#include <sys/systm.h> -#include <sys/unistd.h> #include <miscfs/genfs/genfs.h> @@ -84,10 +75,10 @@ static u_int mq_def_maxmsg = 32; static u_int mq_max_maxmsg = 16 * 32; -static kmutex_t mqlist_mtx; -static pool_cache_t mqmsg_cache; -static LIST_HEAD(, mqueue) mqueue_head; -static struct sysctllog *mqsysctl_log; +static pool_cache_t mqmsg_cache __read_mostly; +static kmutex_t mqlist_lock __cacheline_aligned; +static LIST_HEAD(, mqueue) mqueue_head __cacheline_aligned; +static struct sysctllog * mqsysctl_log; static int mqueue_sysinit(void); static int mqueue_sysfini(bool); @@ -133,7 +124,7 @@ mqmsg_cache = pool_cache_init(MQ_DEF_MSGSIZE, coherency_unit, 0, 0, "mqmsgpl", NULL, IPL_NONE, NULL, NULL, NULL); - mutex_init(&mqlist_mtx, MUTEX_DEFAULT, IPL_NONE); + mutex_init(&mqlist_lock, MUTEX_DEFAULT, IPL_NONE); LIST_INIT(&mqueue_head); error = mqueue_sysctl_init(); @@ -160,13 +151,10 @@ error = syscall_disestablish(NULL, mqueue_syscalls); if (error) return error; - /* - * Check if there are any message queues in use. - * TODO: We shall support forced unload. - */ - mutex_enter(&mqlist_mtx); + /* Check if there are any message queues in use. */ + mutex_enter(&mqlist_lock); inuse = !LIST_EMPTY(&mqueue_head); - mutex_exit(&mqlist_mtx); + mutex_exit(&mqlist_lock); if (inuse) { error = syscall_establish(NULL, mqueue_syscalls); KASSERT(error == 0); @@ -177,7 +165,7 @@ if (mqsysctl_log != NULL) sysctl_teardown(&mqsysctl_log); - mutex_destroy(&mqlist_mtx); + mutex_destroy(&mqlist_lock); pool_cache_destroy(mqmsg_cache); return 0; } @@ -231,6 +219,9 @@ mqueue_freemsg(msg, msz); } } + if (mq->mq_name) { + kmem_free(mq->mq_name, MQ_NAMELEN); + } seldestroy(&mq->mq_rsel); seldestroy(&mq->mq_wsel); cv_destroy(&mq->mq_send_cv); @@ -240,14 +231,16 @@ } /* - * Lookup for file name in general list of message queues. - * => locks the message queue + * mqueue_lookup: lookup for file name in general list of message queues. + * + * => locks the message queue on success */ -static void * -mqueue_lookup(char *name) +static mqueue_t * +mqueue_lookup(const char *name) { - struct mqueue *mq; - KASSERT(mutex_owned(&mqlist_mtx)); + mqueue_t *mq; + + KASSERT(mutex_owned(&mqlist_lock)); LIST_FOREACH(mq, &mqueue_head, mq_list) { if (strncmp(mq->mq_name, name, MQ_NAMELEN) == 0) { @@ -255,33 +248,38 @@ return mq; } } - return NULL; } /* * mqueue_get: get the mqueue from the descriptor. - * => locks the message queue, if found. - * => holds a reference on the file descriptor. + * + * => locks the message queue, if found. + * => holds a reference on the file descriptor. */ static int -mqueue_get(mqd_t mqd, file_t **fpr) +mqueue_get(mqd_t mqd, int fflag, mqueue_t **mqret) { - struct mqueue *mq; + const int fd = (int)mqd; + mqueue_t *mq; file_t *fp; - fp = fd_getfile((int)mqd); + fp = fd_getfile(fd); if (__predict_false(fp == NULL)) { return EBADF; } if (__predict_false(fp->f_type != DTYPE_MQUEUE)) { - fd_putfile((int)mqd); + fd_putfile(fd); + return EBADF; + } + if (fflag && (fp->f_flag & fflag) == 0) { + fd_putfile(fd); return EBADF; } mq = fp->f_data; mutex_enter(&mq->mq_mtx); - *fpr = fp; + *mqret = mq; return 0; } @@ -358,49 +356,111 @@ static int mq_close_fop(file_t *fp) { - struct proc *p = curproc; - struct mqueue *mq = fp->f_data; - bool destroy; + proc_t *p = curproc; + mqueue_t *mq = fp->f_data; + bool destroy = false; - mutex_enter(&mqlist_mtx); mutex_enter(&mq->mq_mtx); - - /* Decrease the counters */ - p->p_mqueue_cnt--; - mq->mq_refcnt--; - - /* Remove notification if registered for this process */ - if (mq->mq_notify_proc == p) - mq->mq_notify_proc = NULL; - - /* - * If this is the last reference and mqueue is marked for unlink, - * remove and later destroy the message queue. - */ - if (mq->mq_refcnt == 0 && (mq->mq_attrib.mq_flags & MQ_UNLINK)) { - LIST_REMOVE(mq, mq_list); - destroy = true; - } else - destroy = false; - + KASSERT(mq->mq_refcnt > 0); + if (--mq->mq_refcnt == 0) { + /* Destroy if the last reference and unlinked. */ + destroy = (mq->mq_attrib.mq_flags & MQ_UNLINKED) != 0; + } mutex_exit(&mq->mq_mtx); - mutex_exit(&mqlist_mtx); - if (destroy) + if (destroy) { mqueue_destroy(mq); - + } + atomic_dec_uint(&p->p_mqueue_cnt); return 0; } static int -mqueue_access(struct mqueue *mq, mode_t mode, kauth_cred_t cred) +mqueue_access(mqueue_t *mq, int access, kauth_cred_t cred) { + mode_t acc_mode = 0; + /* Note the difference between VREAD/VWRITE and FREAD/FWRITE. */ + if (access & FREAD) { + acc_mode |= VREAD; + } + if (access & FWRITE) { + acc_mode |= VWRITE; + } if (genfs_can_access(VNON, mq->mq_mode, mq->mq_euid, - mq->mq_egid, mode, cred)) { + mq->mq_egid, acc_mode, cred)) { return EACCES; } + return 0; +} +static int +mqueue_create(lwp_t *l, char *name, struct mq_attr *uattr, mode_t mode, + int oflag, mqueue_t **mqret) +{ + proc_t *p = l->l_proc; + struct cwdinfo *cwdi = p->p_cwdi; + mqueue_t *mq; + struct mq_attr attr; + u_int i; + + /* Pre-check the limit. */ + if (p->p_mqueue_cnt >= mq_open_max) { + return EMFILE; + } + + /* Empty name is invalid. */ + if (name[0] == '\0') { + return EINVAL; + } + + /* Check for mqueue attributes. */ + if (uattr) { + int error; + + error = copyin(uattr, &attr, sizeof(struct mq_attr)); + if (error) { + return error; + } + if (attr.mq_maxmsg <= 0 || attr.mq_maxmsg > mq_max_maxmsg || + attr.mq_msgsize <= 0 || attr.mq_msgsize > mq_max_msgsize) { + return EINVAL; + } + attr.mq_curmsgs = 0; + } else { + memset(&attr, 0, sizeof(struct mq_attr)); + attr.mq_maxmsg = mq_def_maxmsg; + attr.mq_msgsize = MQ_DEF_MSGSIZE - sizeof(struct mq_msg); + } + + /* + * Allocate new message queue, initialize data structures, copy the + * name attributes. Note that the initial reference is set here. + */ + mq = kmem_zalloc(sizeof(mqueue_t), KM_SLEEP); + + mutex_init(&mq->mq_mtx, MUTEX_DEFAULT, IPL_NONE); + cv_init(&mq->mq_send_cv, "mqsendcv"); + cv_init(&mq->mq_recv_cv, "mqrecvcv"); + for (i = 0; i < (MQ_PQSIZE + 1); i++) { + TAILQ_INIT(&mq->mq_head[i]); + } + selinit(&mq->mq_rsel); + selinit(&mq->mq_wsel); + mq->mq_name = name; + mq->mq_refcnt = 1; + + memcpy(&mq->mq_attrib, &attr, sizeof(struct mq_attr)); + + CTASSERT((O_MASK & (MQ_UNLINKED | MQ_RECEIVE)) == 0); + mq->mq_attrib.mq_flags = (O_MASK & oflag); + + /* Store mode and effective UID with GID. */ + mq->mq_mode = ((mode & ~cwdi->cwdi_cmask) & ALLPERMS) & ~S_ISTXT; + mq->mq_euid = kauth_cred_geteuid(l->l_cred); + mq->mq_egid = kauth_cred_getegid(l->l_cred); + + *mqret = mq; return 0; } @@ -420,93 +480,21 @@ } */ struct proc *p = l->l_proc; struct mqueue *mq, *mq_new = NULL; + int mqd, error, oflag = SCARG(uap, oflag); file_t *fp; char *name; - int mqd, error, oflag; - oflag = SCARG(uap, oflag); - - /* Get the name from the user-space */ - name = kmem_zalloc(MQ_NAMELEN, KM_SLEEP); + /* Get the name from the user-space. */ + name = kmem_alloc(MQ_NAMELEN, KM_SLEEP); error = copyinstr(SCARG(uap, name), name, MQ_NAMELEN - 1, NULL); if (error) { kmem_free(name, MQ_NAMELEN); return error; } - if (oflag & O_CREAT) { - struct cwdinfo *cwdi = p->p_cwdi; - struct mq_attr attr; - u_int i; - - /* Check the limit */ - if (p->p_mqueue_cnt == mq_open_max) { - kmem_free(name, MQ_NAMELEN); - return EMFILE; - } - - /* Empty name is invalid */ - if (name[0] == '\0') { - kmem_free(name, MQ_NAMELEN); - return EINVAL; - } - - /* Check for mqueue attributes */ - if (SCARG(uap, attr)) { - error = copyin(SCARG(uap, attr), &attr, - sizeof(struct mq_attr)); - if (error) { - kmem_free(name, MQ_NAMELEN); - return error; - } - if (attr.mq_maxmsg <= 0 || - attr.mq_maxmsg > mq_max_maxmsg || - attr.mq_msgsize <= 0 || - attr.mq_msgsize > mq_max_msgsize) { - kmem_free(name, MQ_NAMELEN); - return EINVAL; - } - attr.mq_curmsgs = 0; - } else { - memset(&attr, 0, sizeof(struct mq_attr)); - attr.mq_maxmsg = mq_def_maxmsg; - attr.mq_msgsize = - MQ_DEF_MSGSIZE - sizeof(struct mq_msg); - } - - /* - * Allocate new mqueue, initialize data structures, - * copy the name, attributes and set the flag. - */ - mq_new = kmem_zalloc(sizeof(struct mqueue), KM_SLEEP); - - mutex_init(&mq_new->mq_mtx, MUTEX_DEFAULT, IPL_NONE); - cv_init(&mq_new->mq_send_cv, "mqsendcv"); - cv_init(&mq_new->mq_recv_cv, "mqrecvcv"); - for (i = 0; i < (MQ_PQSIZE + 1); i++) { - TAILQ_INIT(&mq_new->mq_head[i]); - } - selinit(&mq_new->mq_rsel); - selinit(&mq_new->mq_wsel); - - strlcpy(mq_new->mq_name, name, MQ_NAMELEN); - memcpy(&mq_new->mq_attrib, &attr, sizeof(struct mq_attr)); - - CTASSERT((O_MASK & (MQ_UNLINK | MQ_RECEIVE)) == 0); - mq_new->mq_attrib.mq_flags = (O_MASK & oflag); - - /* Store mode and effective UID with GID */ - mq_new->mq_mode = ((SCARG(uap, mode) & - ~cwdi->cwdi_cmask) & ALLPERMS) & ~S_ISTXT; - mq_new->mq_euid = kauth_cred_geteuid(l->l_cred); - mq_new->mq_egid = kauth_cred_getegid(l->l_cred); - } - - /* Allocate file structure and descriptor */ + /* Allocate file structure and descriptor. */ error = fd_allocfile(&fp, &mqd); if (error) { - if (mq_new) - mqueue_destroy(mq_new); kmem_free(name, MQ_NAMELEN); return error; } @@ -514,84 +502,86 @@ fp->f_flag = FFLAGS(oflag) & (FREAD | FWRITE); fp->f_ops = &mqops; - /* Look up for mqueue with such name */ - mutex_enter(&mqlist_mtx); + if (oflag & O_CREAT) { + /* Create a new message queue. */ + error = mqueue_create(l, name, SCARG(uap, attr), + SCARG(uap, mode), oflag, &mq_new); + if (error) { + goto err; + } + KASSERT(mq_new != NULL); + } + + /* Lookup for a message queue with such name. */ + mutex_enter(&mqlist_lock); mq = mqueue_lookup(name); if (mq) { - mode_t acc_mode; - KASSERT(mutex_owned(&mq->mq_mtx)); + mutex_exit(&mqlist_lock); - /* Check if mqueue is not marked as unlinking */ - if (mq->mq_attrib.mq_flags & MQ_UNLINK) { - error = EACCES; - goto exit; - } - - /* Fail if O_EXCL is set, and mqueue already exists */ - if ((oflag & O_CREAT) && (oflag & O_EXCL)) { + /* Check for exclusive create. */ + if (oflag & O_EXCL) { + mutex_exit(&mq->mq_mtx); error = EEXIST; - goto exit; + goto err; } - /* - * Check the permissions. Note the difference between - * VREAD/VWRITE and FREAD/FWRITE. - */ - acc_mode = 0; - if (fp->f_flag & FREAD) { - acc_mode |= VREAD; - } - if (fp->f_flag & FWRITE) { - acc_mode |= VWRITE; - } - if (mqueue_access(mq, acc_mode, l->l_cred) != 0) { + /* Verify permissions. */ + if (mqueue_access(mq, fp->f_flag, l->l_cred) != 0) { + mutex_exit(&mq->mq_mtx); error = EACCES; - goto exit; + goto err; } + + /* If we have the access, add a new reference. */ + mq->mq_refcnt++; + mutex_exit(&mq->mq_mtx); } else { - /* Fail if mqueue neither exists, nor we create it */ + /* Fail if not found and not creating. */ if ((oflag & O_CREAT) == 0) { - mutex_exit(&mqlist_mtx); + mutex_exit(&mqlist_lock); KASSERT(mq_new == NULL); - fd_abort(p, fp, mqd); - kmem_free(name, MQ_NAMELEN); - return ENOENT; + error = ENOENT; + goto err; } - /* Check the limit */ - if (p->p_mqueue_cnt == mq_open_max) { + /* Account and check for the limit. */ + if (atomic_inc_uint_nv(&p->p_mqueue_cnt) > mq_open_max) { + mutex_exit(&mqlist_lock); + atomic_dec_uint(&p->p_mqueue_cnt); error = EMFILE; - goto exit; + goto err; } - /* Insert the queue to the list */ + /* Initial timestamps. */ mq = mq_new; - mutex_enter(&mq->mq_mtx); - LIST_INSERT_HEAD(&mqueue_head, mq, mq_list); - mq_new = NULL; getnanotime(&mq->mq_btime); mq->mq_atime = mq->mq_mtime = mq->mq_btime; - } - /* Increase the counters, and make descriptor ready */ - p->p_mqueue_cnt++; - mq->mq_refcnt++; - fp->f_data = mq; -exit: - mutex_exit(&mq->mq_mtx); - mutex_exit(&mqlist_mtx); + /* + * Finally, insert message queue into the list. + * Note: it already has the initial reference. + */ + LIST_INSERT_HEAD(&mqueue_head, mq, mq_list); + mutex_exit(&mqlist_lock); - if (mq_new) - mqueue_destroy(mq_new); + mq_new = NULL; + name = NULL; + } + KASSERT(mq != NULL); + fp->f_data = mq; + fd_affix(p, fp, mqd); + *retval = mqd; +err: if (error) { fd_abort(p, fp, mqd); - } else { - fd_affix(p, fp, mqd); - *retval = mqd; } - kmem_free(name, MQ_NAMELEN); - + if (mq_new) { + /* Note: will free the 'name'. */ + mqueue_destroy(mq_new); + } else if (name) { + kmem_free(name, MQ_NAMELEN); + } return error; } @@ -610,23 +600,16 @@ mq_recv1(mqd_t mqdes, void *msg_ptr, size_t msg_len, u_int *msg_prio, struct timespec *ts, ssize_t *mlen) { - file_t *fp = NULL; struct mqueue *mq; struct mq_msg *msg = NULL; struct mq_attr *mqattr; u_int idx; int error; - /* Get the message queue */ - error = mqueue_get(mqdes, &fp); + error = mqueue_get(mqdes, FREAD, &mq); if (error) { return error; } - mq = fp->f_data; - if ((fp->f_flag & FREAD) == 0) { - error = EBADF; - goto error; - } getnanotime(&mq->mq_atime); mqattr = &mq->mq_attrib; @@ -657,7 +640,7 @@ mqattr->mq_flags |= MQ_RECEIVE; error = cv_timedwait_sig(&mq->mq_send_cv, &mq->mq_mtx, t); mqattr->mq_flags &= ~MQ_RECEIVE; - if (error || (mqattr->mq_flags & MQ_UNLINK)) { + if (error || (mqattr->mq_flags & MQ_UNLINKED)) { error = (error == EWOULDBLOCK) ? ETIMEDOUT : EINTR; goto error; } @@ -770,7 +753,6 @@ mq_send1(mqd_t mqdes, const char *msg_ptr, size_t msg_len, u_int msg_prio, struct timespec *ts) { - file_t *fp = NULL; struct mqueue *mq; struct mq_msg *msg; struct mq_attr *mqattr; @@ -803,17 +785,11 @@ msg->msg_len = msg_len; msg->msg_prio = msg_prio; - /* Get the mqueue */ - error = mqueue_get(mqdes, &fp); + error = mqueue_get(mqdes, FWRITE, &mq); if (error) { mqueue_freemsg(msg, size); return error; } - mq = fp->f_data; - if ((fp->f_flag & FWRITE) == 0) { - error = EBADF; - goto error; - } getnanotime(&mq->mq_mtime); mqattr = &mq->mq_attrib; @@ -839,7 +815,7 @@ t = 0; /* Block until queue becomes available */ error = cv_timedwait_sig(&mq->mq_recv_cv, &mq->mq_mtx, t); - if (error || (mqattr->mq_flags & MQ_UNLINK)) { + if (error || (mqattr->mq_flags & MQ_UNLINKED)) { error = (error == EWOULDBLOCK) ? ETIMEDOUT : error; goto error; } @@ -946,7 +922,6 @@ syscallarg(mqd_t) mqdes; syscallarg(const struct sigevent *) notification; } */ - file_t *fp = NULL; struct mqueue *mq; struct sigevent sig; int error; @@ -962,11 +937,10 @@ return EINVAL; } - error = mqueue_get(SCARG(uap, mqdes), &fp); - if (error) + error = mqueue_get(SCARG(uap, mqdes), 0, &mq); + if (error) { return error; - mq = fp->f_data; - + } if (SCARG(uap, notification)) { /* Register notification: set the signal and target process */ if (mq->mq_notify_proc == NULL) { @@ -995,16 +969,14 @@ syscallarg(mqd_t) mqdes; syscallarg(struct mq_attr *) mqstat; } */ - file_t *fp = NULL; struct mqueue *mq; struct mq_attr attr; int error; - /* Get the message queue */ - error = mqueue_get(SCARG(uap, mqdes), &fp); - if (error) + error = mqueue_get(SCARG(uap, mqdes), 0, &mq); + if (error) { return error; - mq = fp->f_data; + } memcpy(&attr, &mq->mq_attrib, sizeof(struct mq_attr)); mutex_exit(&mq->mq_mtx); fd_putfile((int)SCARG(uap, mqdes)); @@ -1021,7 +993,6 @@ syscallarg(const struct mq_attr *) mqstat; syscallarg(struct mq_attr *) omqstat; } */ - file_t *fp = NULL; struct mqueue *mq; struct mq_attr attr; int error, nonblock; @@ -1031,11 +1002,10 @@ return error; nonblock = (attr.mq_flags & O_NONBLOCK); - /* Get the message queue */ - error = mqueue_get(SCARG(uap, mqdes), &fp); - if (error) + error = mqueue_get(SCARG(uap, mqdes), 0, &mq); + if (error) { return error; - mq = fp->f_data; + } /* Copy the old attributes, if needed */ if (SCARG(uap, omqstat)) { @@ -1070,60 +1040,61 @@ /* { syscallarg(const char *) name; } */ - struct mqueue *mq; + mqueue_t *mq; char *name; int error, refcnt = 0; /* Get the name from the user-space */ - name = kmem_zalloc(MQ_NAMELEN, KM_SLEEP); + name = kmem_alloc(MQ_NAMELEN, KM_SLEEP); error = copyinstr(SCARG(uap, name), name, MQ_NAMELEN - 1, NULL); if (error) { kmem_free(name, MQ_NAMELEN); return error; } - /* Lookup for this file */ - mutex_enter(&mqlist_mtx); + mutex_enter(&mqlist_lock); mq = mqueue_lookup(name); if (mq == NULL) { error = ENOENT; - goto error; + goto err; } + KASSERT(mutex_owned(&mq->mq_mtx)); - /* Check the permissions */ + /* Verify permissions. */ if (kauth_cred_geteuid(l->l_cred) != mq->mq_euid && kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER, NULL)) { mutex_exit(&mq->mq_mtx); error = EACCES; - goto error; + goto err; } - /* Mark message queue as unlinking, before leaving the window */ - mq->mq_attrib.mq_flags |= MQ_UNLINK; + /* Remove and destroy if no references. */ + LIST_REMOVE(mq, mq_list); + refcnt = mq->mq_refcnt; + if (refcnt) { + /* Mark as unlinked, if there are references. */ + mq->mq_attrib.mq_flags |= MQ_UNLINKED; + } - /* Wake up all waiters, if there are such */ + /* Wake up waiters, if there are any. */ cv_broadcast(&mq->mq_send_cv); cv_broadcast(&mq->mq_recv_cv); selnotify(&mq->mq_rsel, POLLHUP, 0); selnotify(&mq->mq_wsel, POLLHUP, 0); - refcnt = mq->mq_refcnt; - if (refcnt == 0) - LIST_REMOVE(mq, mq_list); - mutex_exit(&mq->mq_mtx); -error: - mutex_exit(&mqlist_mtx); - +err: + mutex_exit(&mqlist_lock); /* - * If there are no references - destroy the message - * queue, otherwise, the last mq_close() will do that. + * If last reference - destroy the message queue. Otherwise, + * the last mq_close() call will do that. */ - if (error == 0 && refcnt == 0) + if (!error && refcnt == 0) { mqueue_destroy(mq); - + } kmem_free(name, MQ_NAMELEN); + return error; } Index: src/sys/sys/mqueue.h diff -u src/sys/sys/mqueue.h:1.12 src/sys/sys/mqueue.h:1.13 --- src/sys/sys/mqueue.h:1.12 Sun Nov 1 21:46:09 2009 +++ src/sys/sys/mqueue.h Sun Apr 24 20:17:53 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: mqueue.h,v 1.12 2009/11/01 21:46:09 rmind Exp $ */ +/* $NetBSD: mqueue.h,v 1.13 2011/04/24 20:17:53 rmind Exp $ */ /* * Copyright (c) 2007-2009 Mindaugas Rasiukevicius <rmind at NetBSD org> @@ -52,12 +52,12 @@ #include <sys/types.h> /* - * Flags below are used in mq_flags for internal - * purposes, this is appropriate according to POSIX. + * Flags below are used in mq_flags for internal purposes. + * This is permitted according to POSIX. */ -/* Message queue is unlinking */ -#define MQ_UNLINK 0x10000000 +/* Message queue is unlinked */ +#define MQ_UNLINKED 0x10000000 /* There are receive-waiters */ #define MQ_RECEIVE 0x20000000 @@ -71,9 +71,9 @@ #define MQ_PQSIZE 32 #define MQ_PQRESQ 0 -/* Structure of the message queue */ -struct mqueue { - char mq_name[MQ_NAMELEN]; +/* Structure of the message queue. */ +typedef struct mqueue { + char * mq_name; kmutex_t mq_mtx; kcondvar_t mq_send_cv; kcondvar_t mq_recv_cv; @@ -97,15 +97,15 @@ struct timespec mq_atime; struct timespec mq_mtime; struct timespec mq_btime; -}; +} mqueue_t; -/* Structure of the message */ -struct mq_msg { +/* Structure of the message. */ +typedef struct mq_msg { TAILQ_ENTRY(mq_msg) msg_queue; size_t msg_len; u_int msg_prio; uint8_t msg_ptr[1]; -}; +} mq_msg_t; /* Prototypes */ void mqueue_print_list(void (*pr)(const char *, ...));