summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/os/msg.c
diff options
context:
space:
mode:
authordv142724 <none@none>2006-10-26 09:03:00 -0700
committerdv142724 <none@none>2006-10-26 09:03:00 -0700
commite50383f4b4a232c1643d12a8374521936b4fed9a (patch)
tree4eb0726f0e9acef1625216ee580a314a0cb15d88 /usr/src/uts/common/os/msg.c
parent45143bb76a76a505b56f74b680f21aa9533dabd0 (diff)
downloadillumos-joyent-e50383f4b4a232c1643d12a8374521936b4fed9a.tar.gz
6485031 msgsnd can preallocate small buffers
Diffstat (limited to 'usr/src/uts/common/os/msg.c')
-rw-r--r--usr/src/uts/common/os/msg.c45
1 files changed, 39 insertions, 6 deletions
diff --git a/usr/src/uts/common/os/msg.c b/usr/src/uts/common/os/msg.c
index 713b27d36d..22f04d9e16 100644
--- a/usr/src/uts/common/os/msg.c
+++ b/usr/src/uts/common/os/msg.c
@@ -787,6 +787,8 @@ msgsnap(int msqid, caddr_t buf, size_t bufsz, long msgtyp)
return (0);
}
+#define MSG_PREALLOC_LIMIT 8192
+
/*
* msgsnd system call.
*/
@@ -794,7 +796,7 @@ static int
msgsnd(int msqid, struct ipcmsgbuf *msgp, size_t msgsz, int msgflg)
{
kmsqid_t *qp;
- kmutex_t *lock;
+ kmutex_t *lock = NULL;
struct msg *mp = NULL;
long type;
int error = 0;
@@ -817,8 +819,37 @@ msgsnd(int msqid, struct ipcmsgbuf *msgp, size_t msgsz, int msgflg)
if (type < 1)
return (set_errno(EINVAL));
- if ((lock = ipc_lookup(msq_svc, msqid, (kipc_perm_t **)&qp)) == NULL)
- return (set_errno(EINVAL));
+ /*
+ * We want the value here large enough that most of the
+ * the message operations will use the "lockless" path,
+ * but small enough that a user can not reserve large
+ * chunks of kernel memory unless they have a valid
+ * reason to.
+ */
+ if (msgsz <= MSG_PREALLOC_LIMIT) {
+ /*
+ * We are small enough that we can afford to do the
+ * allocation now. This saves dropping the lock
+ * and then reacquiring the lock.
+ */
+ mp = kmem_zalloc(sizeof (struct msg), KM_SLEEP);
+ mp->msg_copycnt = 1;
+ mp->msg_size = msgsz;
+ if (msgsz) {
+ mp->msg_addr = kmem_alloc(msgsz, KM_SLEEP);
+ if (copyin(STRUCT_FADDR(umsgp, mtext),
+ mp->msg_addr, msgsz) == -1) {
+ error = EFAULT;
+ goto msgsnd_out;
+ }
+ }
+ }
+
+ if ((lock = ipc_lookup(msq_svc, msqid, (kipc_perm_t **)&qp)) == NULL) {
+ error = EINVAL;
+ goto msgsnd_out;
+ }
+
ipc_hold(msq_svc, (kipc_perm_t *)qp);
if (msgsz > qp->msg_qbytes) {
@@ -863,12 +894,13 @@ top:
int failure;
mutex_exit(lock);
+ ASSERT(msgsz > 0);
mp = kmem_zalloc(sizeof (struct msg), KM_SLEEP);
- mp->msg_addr = kmem_zalloc(msgsz, KM_SLEEP);
+ mp->msg_addr = kmem_alloc(msgsz, KM_SLEEP);
mp->msg_size = msgsz;
mp->msg_copycnt = 1;
- failure = msgsz && (copyin(STRUCT_FADDR(umsgp, mtext),
+ failure = (copyin(STRUCT_FADDR(umsgp, mtext),
mp->msg_addr, msgsz) == -1);
lock = ipc_lock(msq_svc, qp->msg_perm.ipc_id);
if (IPC_FREE(&qp->msg_perm)) {
@@ -904,7 +936,8 @@ top:
cv_broadcast(&qp->msg_rcv_cv[0]);
msgsnd_out:
- ipc_rele(msq_svc, (kipc_perm_t *)qp); /* drops lock */
+ if (lock)
+ ipc_rele(msq_svc, (kipc_perm_t *)qp); /* drops lock */
if (error) {
if (mp)