Posix Queues and Msg_Max

POSIX queues and msg_max

No.

That limit is a system-wide limit; that's why it's in /proc/sys. If you want to change it you will have to use the echo command you have already shown.

Is there a way to increase the maximum amount of messages that can be contained in a SysV message queue?

As SYSV IPC are considered deprecated, it is a pity to design brand new applications with thoses old fashioned services.

POSIX message queues are based on a file system. It is usually mounted on /dev/mqueue:

$ ls -la /dev/mqueue
total 0
drwxrwxrwt 2 root root 40 dec. 25 21:02 .
drwxr-xr-x 20 root root 4600 dec. 25 20:51 ..

A message queue is created with mq_open(). The attr parameter provides the ability to set some attributes:

struct mq_attr {
long mq_flags; /* Flags (ignored for mq_open()) */
long mq_maxmsg; /* Max. # of messages on queue */
long mq_msgsize; /* Max. message size (bytes) */
long mq_curmsgs; /* # of messages currently in queue (ignored for mq_open()) */
};

According to the documentation, the /proc/sys/fs/mqueue/msg_max file defines the ceiling value for the maximum number of messages in a queue. In Linux 5.4, its default value is DFLT_MSGMAX (10) and its upper limit is HARD_MSGMAX (65536).

The defaults values are defined in the Linux source code (cf. /include/linux/ipc_namespace.h):

#define DFLT_QUEUESMAX      256
#define MIN_MSGMAX 1
#define DFLT_MSG 10U
#define DFLT_MSGMAX 10
#define HARD_MSGMAX 65536
#define MIN_MSGSIZEMAX 128
#define DFLT_MSGSIZE 8192U
#define DFLT_MSGSIZEMAX 8192
#define HARD_MSGSIZEMAX (16*1024*1024)

Here is an example program which creates a message queue. It receives as parameters the message queue name and the maximum number of messages in the queue:

#include <errno.h>
#include <pthread.h>
#include <mqueue.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
mqd_t mqdes;
struct mq_attr attr;

if (argc != 3) {
fprintf(stderr, "Usage: %s <mq-name> <msg_max>\n", argv[0]);
exit(EXIT_FAILURE);
}

attr.mq_flags = 0;
attr.mq_maxmsg = atoi(argv[2]);
attr.mq_msgsize = 2048;
attr.mq_curmsgs = 0;

mqdes = mq_open(argv[1], O_CREAT | O_RDWR, 0777, &attr);
if (mqdes == (mqd_t) -1) {
perror("mq_open");
return 1;
}

return 0;
}

At execution time we can verify that, by default, we can't go above 10 messages for the queue:

$ gcc mq.c -o mq -lrt
$ ./mq
Usage: ./mq <mq-name> <msg_max>
$ ./mq /q0 5
$ ls -la /dev/mqueue/
total 0
drwxrwxrwt 2 root root 60 dec. 25 21:09 .
drwxr-xr-x 20 root root 4600 dec. 25 20:51 ..
-rwxrwxr-x 1 xxxx xxxx 80 dec. 25 21:09 q0
$ ./mq /q1 9
$ ./mq /q2 10
$ ./mq /q3 11
mq_open: Invalid argument
$ ls -la /dev/mqueue/
total 0
drwxrwxrwt 2 root root 100 dec. 25 21:10 .
drwxr-xr-x 20 root root 4600 dec. 25 20:51 ..
-rwxrwxr-x 1 xxxx xxxx 80 dec. 25 21:09 q0
-rwxrwxr-x 1 xxxx xxxx 80 dec. 25 21:10 q1
-rwxrwxr-x 1 xxxx xxxx 80 dec. 25 21:10 q2

Let's change the ceiling value from 10 to 256 for msg_max:

$ cat /proc/sys/fs/mqueue/msg_max
10
$ sudo sh -c "echo 256 > /proc/sys/fs/mqueue/msg_max"
$ cat /proc/sys/fs/mqueue/msg_max
256

Now it is possible to create message queues with up to 256 messages:

$ ./mq /q3 11
$ ./mq /q4 256
$ ./mq /q5 257
mq_open: Invalid argument
$ ls -la /dev/mqueue/
total 0
drwxrwxrwt 2 root root 140 dec. 25 21:16 .
drwxr-xr-x 20 root root 4600 dec. 25 20:51 ..
-rwxrwxr-x 1 xxxx xxxx 80 dec. 25 21:09 q0
-rwxrwxr-x 1 xxxx xxxx 80 dec. 25 21:10 q1
-rwxrwxr-x 1 xxxx xxxx 80 dec. 25 21:10 q2
-rwxrwxr-x 1 xxxx xxxx 80 dec. 25 21:15 q3
-rwxrwxr-x 1 xxxx xxxx 80 dec. 25 21:16 q4

But as you say, increasing the ceiling value requires super user rights. It could be possible to create a "setuid helper" which increases the ceiling value. For example, the following program sets the ceiling value passed as parameter:

#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>

int main(int argc, char *argv[])
{
int fd;
int rc;
int msg_max;

if (argc != 2) {
fprintf(stderr, "Usage: %s <msg_max>\n", argv[0]);
return 1;
}

fd = open("/proc/sys/fs/mqueue/msg_max", O_RDWR);
if (fd < 0) {
perror("open()");
return 1;
}

rc = write(fd, argv[1], strlen(argv[1]));
if (rc != strlen(argv[1])) {
if (rc >= 0) {
errno = EIO;
}
perror("write()");
return 1;
}

close(fd);

return 0;
}

We can build it, change its owner/group to root and add the setuid bit:

$ gcc mq_helper.c -o mq_helper
$ sudo chown root mq_helper
$ sudo chgrp root mq_helper
$ sudo chmod 4555 mq_helper
$ ls -l mq_helper
-r-sr-xr-x 1 root root 17016 dec. 25 21:45 mq_helper

Then, it is possible to run this program from a non super user account to change the ceiling value of msg_max:

$ cat /proc/sys/fs/mqueue/msg_max
256
$ ./mq_helper 98
$ cat /proc/sys/fs/mqueue/msg_max
98

adjust number of messages in posix message queue

In the linux manual page for posix message queue, you can read how to tune the related kernel configuration via the /proc filesystem.

In particular /proc/sys/fs/mqueue/msg_max is what you are looking for:

This file can be used to view and change the ceiling value for the maximum number of messages in a queue. This value acts as a ceiling on the attr->mq_maxmsg argument given to mq_open(3). The default value for msg_max is 10. The minimum value is 1 (10 in kernels before 2.6.28). The upper limit is HARD_MAX: (131072 / sizeof(void *)) (32768 on Linux/86). This limit is ignored for privileged processes (CAP_SYS_RESOURCE), but the HARD_MAX ceiling is nevertheless imposed.

edit
As explained in the mq_open(2), mq_getattr(3) and mq_send(3) manual pages, the mq_maxmsg value sets the maximum number of message that the queue can handle without blocking (or returning EAGAIN in case of non-blocking queues). If you mq_open a queue with mq_maxmsg = 5 and the kernel configuration in /proc is 10 (the default, AFAIK) than the queue will accept 5 message without blocking. If you mq_open a queue with mq_maxmsg = 15 and the kernel configuration in /proc is 10, the queue will accept 10 message. That is: you can create a queue that hold a max number of message that is lower than the maximum number of messages that the kernel accepts, but not greater.

Is it possible to open message queue in linux with huge number of elements?

You have encountered RLIMIT_MSGQUEUE limit, see mq_overview(7):

Resource limit

The RLIMIT_MSGQUEUE resource limit, which places a limit on the
amount of space that can be consumed by all of the message queues
belonging to a process's real user ID, is described in getrlimit(2).

Increase it before calling mq_open(), e.g. like this:

...
#include <sys/resource.h>

int main(int argc, char** argv)
{
struct rlimit rlim;
rlim.rlim_cur = RLIM_INFINITY;
rlim.rlim_max = RLIM_INFINITY;

if (setrlimit(RLIMIT_MSGQUEUE, &rlim) == -1) {
perror("setrlimit");
return 1;
}

...

You need root privileges for that (or CAP_SYS_RESOURCE capability, I guess).


Linux kernel really returns EMFILE for this case, check it here:

if (u->mq_bytes + mq_bytes < u->mq_bytes ||
u->mq_bytes + mq_bytes > rlimit(RLIMIT_MSGQUEUE)) {
spin_unlock(&mq_lock);
/* mqueue_evict_inode() releases info->messages */
ret = -EMFILE;
goto out_inode;
}

The reason for EMFILE here is probably that it's the most close error code from those specified in POSIX; EMFILE is the only error code that reflects reaching a per-process limitation.

POSIX doesn't specify a more precise error code for RLIMIT_MSGQUEUE because it is Linux-specific.

Posix Queues. Receive and Priorities

It's possible because you never unlink your queue that you are unknowingly working with a previously created one. If the old queue was created with a message size larger than the msg_len parameter you are passing to mq_receive, that would explain your "Message too long" (EMSGSIZE) errors.

Try deleting any existing queues before you run the program. If they aren't already mounted you can mount the queues like so:

sudo mkdir /dev/mqueue
sudo mount -t mqueue none /dev/mqueue

You can then perform normal file operations like ls /dev/mqueue and rm /dev/mqueue/queue.txt.

(Note: "queue.txt" is a pretty awful name. It's not a text file.)



Related Topics



Leave a reply



Submit