diff options
Diffstat (limited to 'ipc/msg.c')
-rw-r--r-- | ipc/msg.c | 188 |
1 files changed, 92 insertions, 96 deletions
@@ -39,12 +39,10 @@ | |||
39 | #include <linux/ipc_namespace.h> | 39 | #include <linux/ipc_namespace.h> |
40 | 40 | ||
41 | #include <asm/current.h> | 41 | #include <asm/current.h> |
42 | #include <asm/uaccess.h> | 42 | #include <linux/uaccess.h> |
43 | #include "util.h" | 43 | #include "util.h" |
44 | 44 | ||
45 | /* | 45 | /* one msg_receiver structure for each sleeping receiver */ |
46 | * one msg_receiver structure for each sleeping receiver: | ||
47 | */ | ||
48 | struct msg_receiver { | 46 | struct msg_receiver { |
49 | struct list_head r_list; | 47 | struct list_head r_list; |
50 | struct task_struct *r_tsk; | 48 | struct task_struct *r_tsk; |
@@ -53,6 +51,12 @@ struct msg_receiver { | |||
53 | long r_msgtype; | 51 | long r_msgtype; |
54 | long r_maxsize; | 52 | long r_maxsize; |
55 | 53 | ||
54 | /* | ||
55 | * Mark r_msg volatile so that the compiler | ||
56 | * does not try to get smart and optimize | ||
57 | * it. We rely on this for the lockless | ||
58 | * receive algorithm. | ||
59 | */ | ||
56 | struct msg_msg *volatile r_msg; | 60 | struct msg_msg *volatile r_msg; |
57 | }; | 61 | }; |
58 | 62 | ||
@@ -70,75 +74,6 @@ struct msg_sender { | |||
70 | 74 | ||
71 | #define msg_ids(ns) ((ns)->ids[IPC_MSG_IDS]) | 75 | #define msg_ids(ns) ((ns)->ids[IPC_MSG_IDS]) |
72 | 76 | ||
73 | static void freeque(struct ipc_namespace *, struct kern_ipc_perm *); | ||
74 | static int newque(struct ipc_namespace *, struct ipc_params *); | ||
75 | #ifdef CONFIG_PROC_FS | ||
76 | static int sysvipc_msg_proc_show(struct seq_file *s, void *it); | ||
77 | #endif | ||
78 | |||
79 | /* | ||
80 | * Scale msgmni with the available lowmem size: the memory dedicated to msg | ||
81 | * queues should occupy at most 1/MSG_MEM_SCALE of lowmem. | ||
82 | * Also take into account the number of nsproxies created so far. | ||
83 | * This should be done staying within the (MSGMNI , IPCMNI/nr_ipc_ns) range. | ||
84 | */ | ||
85 | void recompute_msgmni(struct ipc_namespace *ns) | ||
86 | { | ||
87 | struct sysinfo i; | ||
88 | unsigned long allowed; | ||
89 | int nb_ns; | ||
90 | |||
91 | si_meminfo(&i); | ||
92 | allowed = (((i.totalram - i.totalhigh) / MSG_MEM_SCALE) * i.mem_unit) | ||
93 | / MSGMNB; | ||
94 | nb_ns = atomic_read(&nr_ipc_ns); | ||
95 | allowed /= nb_ns; | ||
96 | |||
97 | if (allowed < MSGMNI) { | ||
98 | ns->msg_ctlmni = MSGMNI; | ||
99 | return; | ||
100 | } | ||
101 | |||
102 | if (allowed > IPCMNI / nb_ns) { | ||
103 | ns->msg_ctlmni = IPCMNI / nb_ns; | ||
104 | return; | ||
105 | } | ||
106 | |||
107 | ns->msg_ctlmni = allowed; | ||
108 | } | ||
109 | |||
110 | void msg_init_ns(struct ipc_namespace *ns) | ||
111 | { | ||
112 | ns->msg_ctlmax = MSGMAX; | ||
113 | ns->msg_ctlmnb = MSGMNB; | ||
114 | |||
115 | recompute_msgmni(ns); | ||
116 | |||
117 | atomic_set(&ns->msg_bytes, 0); | ||
118 | atomic_set(&ns->msg_hdrs, 0); | ||
119 | ipc_init_ids(&ns->ids[IPC_MSG_IDS]); | ||
120 | } | ||
121 | |||
122 | #ifdef CONFIG_IPC_NS | ||
123 | void msg_exit_ns(struct ipc_namespace *ns) | ||
124 | { | ||
125 | free_ipcs(ns, &msg_ids(ns), freeque); | ||
126 | idr_destroy(&ns->ids[IPC_MSG_IDS].ipcs_idr); | ||
127 | } | ||
128 | #endif | ||
129 | |||
130 | void __init msg_init(void) | ||
131 | { | ||
132 | msg_init_ns(&init_ipc_ns); | ||
133 | |||
134 | printk(KERN_INFO "msgmni has been set to %d\n", | ||
135 | init_ipc_ns.msg_ctlmni); | ||
136 | |||
137 | ipc_init_proc_interface("sysvipc/msg", | ||
138 | " key msqid perms cbytes qnum lspid lrpid uid gid cuid cgid stime rtime ctime\n", | ||
139 | IPC_MSG_IDS, sysvipc_msg_proc_show); | ||
140 | } | ||
141 | |||
142 | static inline struct msg_queue *msq_obtain_object(struct ipc_namespace *ns, int id) | 77 | static inline struct msg_queue *msq_obtain_object(struct ipc_namespace *ns, int id) |
143 | { | 78 | { |
144 | struct kern_ipc_perm *ipcp = ipc_obtain_object(&msg_ids(ns), id); | 79 | struct kern_ipc_perm *ipcp = ipc_obtain_object(&msg_ids(ns), id); |
@@ -227,7 +162,7 @@ static int newque(struct ipc_namespace *ns, struct ipc_params *params) | |||
227 | static inline void ss_add(struct msg_queue *msq, struct msg_sender *mss) | 162 | static inline void ss_add(struct msg_queue *msq, struct msg_sender *mss) |
228 | { | 163 | { |
229 | mss->tsk = current; | 164 | mss->tsk = current; |
230 | current->state = TASK_INTERRUPTIBLE; | 165 | __set_current_state(TASK_INTERRUPTIBLE); |
231 | list_add_tail(&mss->list, &msq->q_senders); | 166 | list_add_tail(&mss->list, &msq->q_senders); |
232 | } | 167 | } |
233 | 168 | ||
@@ -306,15 +241,14 @@ static inline int msg_security(struct kern_ipc_perm *ipcp, int msgflg) | |||
306 | SYSCALL_DEFINE2(msgget, key_t, key, int, msgflg) | 241 | SYSCALL_DEFINE2(msgget, key_t, key, int, msgflg) |
307 | { | 242 | { |
308 | struct ipc_namespace *ns; | 243 | struct ipc_namespace *ns; |
309 | struct ipc_ops msg_ops; | 244 | static const struct ipc_ops msg_ops = { |
245 | .getnew = newque, | ||
246 | .associate = msg_security, | ||
247 | }; | ||
310 | struct ipc_params msg_params; | 248 | struct ipc_params msg_params; |
311 | 249 | ||
312 | ns = current->nsproxy->ipc_ns; | 250 | ns = current->nsproxy->ipc_ns; |
313 | 251 | ||
314 | msg_ops.getnew = newque; | ||
315 | msg_ops.associate = msg_security; | ||
316 | msg_ops.more_checks = NULL; | ||
317 | |||
318 | msg_params.key = key; | 252 | msg_params.key = key; |
319 | msg_params.flg = msgflg; | 253 | msg_params.flg = msgflg; |
320 | 254 | ||
@@ -612,23 +546,22 @@ SYSCALL_DEFINE3(msgctl, int, msqid, int, cmd, struct msqid_ds __user *, buf) | |||
612 | 546 | ||
613 | static int testmsg(struct msg_msg *msg, long type, int mode) | 547 | static int testmsg(struct msg_msg *msg, long type, int mode) |
614 | { | 548 | { |
615 | switch (mode) | 549 | switch (mode) { |
616 | { | 550 | case SEARCH_ANY: |
617 | case SEARCH_ANY: | 551 | case SEARCH_NUMBER: |
618 | case SEARCH_NUMBER: | 552 | return 1; |
553 | case SEARCH_LESSEQUAL: | ||
554 | if (msg->m_type <= type) | ||
619 | return 1; | 555 | return 1; |
620 | case SEARCH_LESSEQUAL: | 556 | break; |
621 | if (msg->m_type <= type) | 557 | case SEARCH_EQUAL: |
622 | return 1; | 558 | if (msg->m_type == type) |
623 | break; | 559 | return 1; |
624 | case SEARCH_EQUAL: | 560 | break; |
625 | if (msg->m_type == type) | 561 | case SEARCH_NOTEQUAL: |
626 | return 1; | 562 | if (msg->m_type != type) |
627 | break; | 563 | return 1; |
628 | case SEARCH_NOTEQUAL: | 564 | break; |
629 | if (msg->m_type != type) | ||
630 | return 1; | ||
631 | break; | ||
632 | } | 565 | } |
633 | return 0; | 566 | return 0; |
634 | } | 567 | } |
@@ -978,7 +911,7 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl | |||
978 | else | 911 | else |
979 | msr_d.r_maxsize = bufsz; | 912 | msr_d.r_maxsize = bufsz; |
980 | msr_d.r_msg = ERR_PTR(-EAGAIN); | 913 | msr_d.r_msg = ERR_PTR(-EAGAIN); |
981 | current->state = TASK_INTERRUPTIBLE; | 914 | __set_current_state(TASK_INTERRUPTIBLE); |
982 | 915 | ||
983 | ipc_unlock_object(&msq->q_perm); | 916 | ipc_unlock_object(&msq->q_perm); |
984 | rcu_read_unlock(); | 917 | rcu_read_unlock(); |
@@ -1056,6 +989,57 @@ SYSCALL_DEFINE5(msgrcv, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz, | |||
1056 | return do_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg, do_msg_fill); | 989 | return do_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg, do_msg_fill); |
1057 | } | 990 | } |
1058 | 991 | ||
992 | /* | ||
993 | * Scale msgmni with the available lowmem size: the memory dedicated to msg | ||
994 | * queues should occupy at most 1/MSG_MEM_SCALE of lowmem. | ||
995 | * Also take into account the number of nsproxies created so far. | ||
996 | * This should be done staying within the (MSGMNI , IPCMNI/nr_ipc_ns) range. | ||
997 | */ | ||
998 | void recompute_msgmni(struct ipc_namespace *ns) | ||
999 | { | ||
1000 | struct sysinfo i; | ||
1001 | unsigned long allowed; | ||
1002 | int nb_ns; | ||
1003 | |||
1004 | si_meminfo(&i); | ||
1005 | allowed = (((i.totalram - i.totalhigh) / MSG_MEM_SCALE) * i.mem_unit) | ||
1006 | / MSGMNB; | ||
1007 | nb_ns = atomic_read(&nr_ipc_ns); | ||
1008 | allowed /= nb_ns; | ||
1009 | |||
1010 | if (allowed < MSGMNI) { | ||
1011 | ns->msg_ctlmni = MSGMNI; | ||
1012 | return; | ||
1013 | } | ||
1014 | |||
1015 | if (allowed > IPCMNI / nb_ns) { | ||
1016 | ns->msg_ctlmni = IPCMNI / nb_ns; | ||
1017 | return; | ||
1018 | } | ||
1019 | |||
1020 | ns->msg_ctlmni = allowed; | ||
1021 | } | ||
1022 | |||
1023 | void msg_init_ns(struct ipc_namespace *ns) | ||
1024 | { | ||
1025 | ns->msg_ctlmax = MSGMAX; | ||
1026 | ns->msg_ctlmnb = MSGMNB; | ||
1027 | |||
1028 | recompute_msgmni(ns); | ||
1029 | |||
1030 | atomic_set(&ns->msg_bytes, 0); | ||
1031 | atomic_set(&ns->msg_hdrs, 0); | ||
1032 | ipc_init_ids(&ns->ids[IPC_MSG_IDS]); | ||
1033 | } | ||
1034 | |||
1035 | #ifdef CONFIG_IPC_NS | ||
1036 | void msg_exit_ns(struct ipc_namespace *ns) | ||
1037 | { | ||
1038 | free_ipcs(ns, &msg_ids(ns), freeque); | ||
1039 | idr_destroy(&ns->ids[IPC_MSG_IDS].ipcs_idr); | ||
1040 | } | ||
1041 | #endif | ||
1042 | |||
1059 | #ifdef CONFIG_PROC_FS | 1043 | #ifdef CONFIG_PROC_FS |
1060 | static int sysvipc_msg_proc_show(struct seq_file *s, void *it) | 1044 | static int sysvipc_msg_proc_show(struct seq_file *s, void *it) |
1061 | { | 1045 | { |
@@ -1080,3 +1064,15 @@ static int sysvipc_msg_proc_show(struct seq_file *s, void *it) | |||
1080 | msq->q_ctime); | 1064 | msq->q_ctime); |
1081 | } | 1065 | } |
1082 | #endif | 1066 | #endif |
1067 | |||
1068 | void __init msg_init(void) | ||
1069 | { | ||
1070 | msg_init_ns(&init_ipc_ns); | ||
1071 | |||
1072 | printk(KERN_INFO "msgmni has been set to %d\n", | ||
1073 | init_ipc_ns.msg_ctlmni); | ||
1074 | |||
1075 | ipc_init_proc_interface("sysvipc/msg", | ||
1076 | " key msqid perms cbytes qnum lspid lrpid uid gid cuid cgid stime rtime ctime\n", | ||
1077 | IPC_MSG_IDS, sysvipc_msg_proc_show); | ||
1078 | } | ||