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 *, ...));