summaryrefslogtreecommitdiffstats
path: root/ipc/mqueue.c
diff options
context:
space:
mode:
authorDavidlohr Bueso <dave@stgolabs.net>2019-05-14 18:46:26 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2019-05-14 22:52:52 -0400
commita5091fda4e3c202aeb1728a86d0fcd20fd0f4f5e (patch)
treece1b9afe61db8786cae4a5576e599d0f6d46d8e0 /ipc/mqueue.c
parent0ecb58210bd9de14df62a614be07428ef10f9469 (diff)
ipc/mqueue: optimize msg_get()
Our msg priorities became an rbtree as of d6629859b36d ("ipc/mqueue: improve performance of send/recv"). However, consuming a msg in msg_get() remains logarithmic (still being better than the case before of course). By applying well known techniques to cache pointers we can have the node with the highest priority in O(1), which is specially nice for the rt cases. Furthermore, some callers can call msg_get() in a loop. A new msg_tree_erase() helper is also added to encapsulate the tree removal and node_cache game. Passes ltp mq testcases. Link: http://lkml.kernel.org/r/20190321190216.1719-2-dave@stgolabs.net Signed-off-by: Davidlohr Bueso <dbueso@suse.de> Cc: Manfred Spraul <manfred@colorfullife.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'ipc/mqueue.c')
-rw-r--r--ipc/mqueue.c60
1 files changed, 35 insertions, 25 deletions
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 8c6a04111fde..216cad1ff0d0 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -76,6 +76,7 @@ struct mqueue_inode_info {
76 wait_queue_head_t wait_q; 76 wait_queue_head_t wait_q;
77 77
78 struct rb_root msg_tree; 78 struct rb_root msg_tree;
79 struct rb_node *msg_tree_rightmost;
79 struct posix_msg_tree_node *node_cache; 80 struct posix_msg_tree_node *node_cache;
80 struct mq_attr attr; 81 struct mq_attr attr;
81 82
@@ -131,6 +132,7 @@ static int msg_insert(struct msg_msg *msg, struct mqueue_inode_info *info)
131{ 132{
132 struct rb_node **p, *parent = NULL; 133 struct rb_node **p, *parent = NULL;
133 struct posix_msg_tree_node *leaf; 134 struct posix_msg_tree_node *leaf;
135 bool rightmost = true;
134 136
135 p = &info->msg_tree.rb_node; 137 p = &info->msg_tree.rb_node;
136 while (*p) { 138 while (*p) {
@@ -139,9 +141,10 @@ static int msg_insert(struct msg_msg *msg, struct mqueue_inode_info *info)
139 141
140 if (likely(leaf->priority == msg->m_type)) 142 if (likely(leaf->priority == msg->m_type))
141 goto insert_msg; 143 goto insert_msg;
142 else if (msg->m_type < leaf->priority) 144 else if (msg->m_type < leaf->priority) {
143 p = &(*p)->rb_left; 145 p = &(*p)->rb_left;
144 else 146 rightmost = false;
147 } else
145 p = &(*p)->rb_right; 148 p = &(*p)->rb_right;
146 } 149 }
147 if (info->node_cache) { 150 if (info->node_cache) {
@@ -154,6 +157,10 @@ static int msg_insert(struct msg_msg *msg, struct mqueue_inode_info *info)
154 INIT_LIST_HEAD(&leaf->msg_list); 157 INIT_LIST_HEAD(&leaf->msg_list);
155 } 158 }
156 leaf->priority = msg->m_type; 159 leaf->priority = msg->m_type;
160
161 if (rightmost)
162 info->msg_tree_rightmost = &leaf->rb_node;
163
157 rb_link_node(&leaf->rb_node, parent, p); 164 rb_link_node(&leaf->rb_node, parent, p);
158 rb_insert_color(&leaf->rb_node, &info->msg_tree); 165 rb_insert_color(&leaf->rb_node, &info->msg_tree);
159insert_msg: 166insert_msg:
@@ -163,23 +170,35 @@ insert_msg:
163 return 0; 170 return 0;
164} 171}
165 172
173static inline void msg_tree_erase(struct posix_msg_tree_node *leaf,
174 struct mqueue_inode_info *info)
175{
176 struct rb_node *node = &leaf->rb_node;
177
178 if (info->msg_tree_rightmost == node)
179 info->msg_tree_rightmost = rb_prev(node);
180
181 rb_erase(node, &info->msg_tree);
182 if (info->node_cache) {
183 kfree(leaf);
184 } else {
185 info->node_cache = leaf;
186 }
187}
188
166static inline struct msg_msg *msg_get(struct mqueue_inode_info *info) 189static inline struct msg_msg *msg_get(struct mqueue_inode_info *info)
167{ 190{
168 struct rb_node **p, *parent = NULL; 191 struct rb_node *parent = NULL;
169 struct posix_msg_tree_node *leaf; 192 struct posix_msg_tree_node *leaf;
170 struct msg_msg *msg; 193 struct msg_msg *msg;
171 194
172try_again: 195try_again:
173 p = &info->msg_tree.rb_node; 196 /*
174 while (*p) { 197 * During insert, low priorities go to the left and high to the
175 parent = *p; 198 * right. On receive, we want the highest priorities first, so
176 /* 199 * walk all the way to the right.
177 * During insert, low priorities go to the left and high to the 200 */
178 * right. On receive, we want the highest priorities first, so 201 parent = info->msg_tree_rightmost;
179 * walk all the way to the right.
180 */
181 p = &(*p)->rb_right;
182 }
183 if (!parent) { 202 if (!parent) {
184 if (info->attr.mq_curmsgs) { 203 if (info->attr.mq_curmsgs) {
185 pr_warn_once("Inconsistency in POSIX message queue, " 204 pr_warn_once("Inconsistency in POSIX message queue, "
@@ -194,24 +213,14 @@ try_again:
194 pr_warn_once("Inconsistency in POSIX message queue, " 213 pr_warn_once("Inconsistency in POSIX message queue, "
195 "empty leaf node but we haven't implemented " 214 "empty leaf node but we haven't implemented "
196 "lazy leaf delete!\n"); 215 "lazy leaf delete!\n");
197 rb_erase(&leaf->rb_node, &info->msg_tree); 216 msg_tree_erase(leaf, info);
198 if (info->node_cache) {
199 kfree(leaf);
200 } else {
201 info->node_cache = leaf;
202 }
203 goto try_again; 217 goto try_again;
204 } else { 218 } else {
205 msg = list_first_entry(&leaf->msg_list, 219 msg = list_first_entry(&leaf->msg_list,
206 struct msg_msg, m_list); 220 struct msg_msg, m_list);
207 list_del(&msg->m_list); 221 list_del(&msg->m_list);
208 if (list_empty(&leaf->msg_list)) { 222 if (list_empty(&leaf->msg_list)) {
209 rb_erase(&leaf->rb_node, &info->msg_tree); 223 msg_tree_erase(leaf, info);
210 if (info->node_cache) {
211 kfree(leaf);
212 } else {
213 info->node_cache = leaf;
214 }
215 } 224 }
216 } 225 }
217 info->attr.mq_curmsgs--; 226 info->attr.mq_curmsgs--;
@@ -254,6 +263,7 @@ static struct inode *mqueue_get_inode(struct super_block *sb,
254 info->qsize = 0; 263 info->qsize = 0;
255 info->user = NULL; /* set when all is ok */ 264 info->user = NULL; /* set when all is ok */
256 info->msg_tree = RB_ROOT; 265 info->msg_tree = RB_ROOT;
266 info->msg_tree_rightmost = NULL;
257 info->node_cache = NULL; 267 info->node_cache = NULL;
258 memset(&info->attr, 0, sizeof(info->attr)); 268 memset(&info->attr, 0, sizeof(info->attr));
259 info->attr.mq_maxmsg = min(ipc_ns->mq_msg_max, 269 info->attr.mq_maxmsg = min(ipc_ns->mq_msg_max,