From 5b5c4d1a1440e94994c73dddbad7be0676cd8b9a Mon Sep 17 00:00:00 2001 From: Doug Ledford Date: Thu, 31 May 2012 16:26:30 -0700 Subject: ipc/mqueue: update maximums for the mqueue subsystem Commit b231cca4381e ("message queues: increase range limits") changed the maximum size of a message in a message queue from INT_MAX to 8192*128. Unfortunately, we had customers that relied on a size much larger than 8192*128 on their production systems. After reviewing POSIX, we found that it is silent on the maximum message size. We did find a couple other areas in which it was not silent. Fix up the mqueue maximums so that the customer's system can continue to work, and document both the POSIX and real world requirements in ipc_namespace.h so that we don't have this issue crop back up. Also, commit 9cf18e1dd74cd0 ("ipc: HARD_MSGMAX should be higher not lower on 64bit") fiddled with HARD_MSGMAX without realizing that the number was intentionally in place to limit the msg queue depth to one that was small enough to kmalloc an array of pointers (hence why we divided 128k by sizeof(long)). If we wish to meet POSIX requirements, we have no choice but to change our allocation to a vmalloc instead (at least for the large queue size case). With that, it's possible to increase our allowed maximum to the POSIX requirements (or more if we choose). [sfr@canb.auug.org.au: using vmalloc requires including vmalloc.h] Signed-off-by: Doug Ledford Cc: Serge E. Hallyn Cc: Amerigo Wang Cc: Joe Korty Cc: Jiri Slaby Acked-by: KOSAKI Motohiro Cc: Manfred Spraul Signed-off-by: Stephen Rothwell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- ipc/mqueue.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'ipc') diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 6e10a55a78c5..f8eba5e46c5a 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -152,7 +153,10 @@ static struct inode *mqueue_get_inode(struct super_block *sb, info->attr.mq_msgsize = attr->mq_msgsize; } mq_msg_tblsz = info->attr.mq_maxmsg * sizeof(struct msg_msg *); - info->messages = kmalloc(mq_msg_tblsz, GFP_KERNEL); + if (mq_msg_tblsz > KMALLOC_MAX_SIZE) + info->messages = vmalloc(mq_msg_tblsz); + else + info->messages = kmalloc(mq_msg_tblsz, GFP_KERNEL); if (!info->messages) goto out_inode; @@ -262,7 +266,10 @@ static void mqueue_evict_inode(struct inode *inode) spin_lock(&info->lock); for (i = 0; i < info->attr.mq_curmsgs; i++) free_msg(info->messages[i]); - kfree(info->messages); + if (info->attr.mq_maxmsg * sizeof(struct msg_msg *) > KMALLOC_MAX_SIZE) + vfree(info->messages); + else + kfree(info->messages); spin_unlock(&info->lock); /* Total amount of bytes accounted for the mqueue */ -- cgit v1.2.3