● お題
mq_open()がerrno==EMFILEで失敗した
● マニュアル
man 3 mq_openによれば、
https://man7.org/linux/man-pages/man3/mq_open.3.html
- プロセスあたりのfile descriptor数上限に引っかかった -> RLIMIT_NOFILE(ulimit -n) を確認する
だが、該当しているように見えない。
ENFILEの可能性も考え、/proc/sys/fs/file-max と /proc/sys/fs/file-nr を確認するも、こちらも問題なし。
● mqueueのsysctlパラメータ
/proc/sys/fs/mqueue/ にこんなのがある
- msg_max --- 1つのキューに入れられるメッセージの最大個を変更するときの上限
- msg_default --- mq_open()の引数で特に指定しなかったときの新規作成された1つのキューに入れられるメッセージの最大個
- msgsize_max ----- 1メッセージの最大サイズを変更するときの上限
- msgsize_default ---- mq_open()の引数で特に指定しなかったときの新規作成されるキューへ入れる1メッセージの最大サイズ
- queues_max ----- システム全体で作れるqueueの個数
いずれも特権(CAP_SYS_RESOURCE)があれば制限を受けない。
mq_open()のエラーとなると、queues_maxが怪しいが、/dev/mqueue を見る限りキューの個数の上限に達したようには見えない。
● limitパラメータ
man 7 mq_overview をきっちり読むまでこれに気づかなかった。
https://man7.org/linux/man-pages/man7/mq_overview.7.html
RLIMIT_MSGQUEUE (ulimit -q) というのがある。1ユーザ(uid)あたりで使えるmqueueのメッセージの合計サイズの条件になる。
管理情報も含むため、メッセージの中身のバイト数の合計よりもちょっと厳しく働く。
サイズを予約するときにチェックする?という方向のため、mq_open()のタイミングで失敗する。
たとえ CAP_SYS_RESOURCE を持っていても制限を回避できない
CAP_SYS_RESOURCE を持ってるとhard limitを変更する(ulimit -q unlimited)ことができ、制限を回避できる。
結局原因はこれだった。limitを変更すると動作するようになった。
● その他
- /dev/mqueueは、存在するqueueの名前を確認できる程度で、ここを直接catしたりduしたりはできない
- /dev/mqueue で rm すると、誰も開いていないqueueを名前指定で削除できる
- mqueueのnamespaceは ipc_namespaces になる。mqueueとsysvipcとが対象にある。