|
39 | 39 | #include <linux/nsproxy.h> |
40 | 40 | #include <linux/ipc_namespace.h> |
41 | 41 | #include <linux/rhashtable.h> |
| 42 | +#include <linux/percpu_counter.h> |
42 | 43 |
|
43 | 44 | #include <asm/current.h> |
44 | 45 | #include <linux/uaccess.h> |
@@ -285,10 +286,10 @@ static void freeque(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp) |
285 | 286 | rcu_read_unlock(); |
286 | 287 |
|
287 | 288 | list_for_each_entry_safe(msg, t, &msq->q_messages, m_list) { |
288 | | - atomic_dec(&ns->msg_hdrs); |
| 289 | + percpu_counter_sub_local(&ns->percpu_msg_hdrs, 1); |
289 | 290 | free_msg(msg); |
290 | 291 | } |
291 | | - atomic_sub(msq->q_cbytes, &ns->msg_bytes); |
| 292 | + percpu_counter_sub_local(&ns->percpu_msg_bytes, msq->q_cbytes); |
292 | 293 | ipc_update_pid(&msq->q_lspid, NULL); |
293 | 294 | ipc_update_pid(&msq->q_lrpid, NULL); |
294 | 295 | ipc_rcu_putref(&msq->q_perm, msg_rcu_free); |
@@ -495,17 +496,22 @@ static int msgctl_info(struct ipc_namespace *ns, int msqid, |
495 | 496 | msginfo->msgssz = MSGSSZ; |
496 | 497 | msginfo->msgseg = MSGSEG; |
497 | 498 | down_read(&msg_ids(ns).rwsem); |
498 | | - if (cmd == MSG_INFO) { |
| 499 | + if (cmd == MSG_INFO) |
499 | 500 | msginfo->msgpool = msg_ids(ns).in_use; |
500 | | - msginfo->msgmap = atomic_read(&ns->msg_hdrs); |
501 | | - msginfo->msgtql = atomic_read(&ns->msg_bytes); |
| 501 | + max_idx = ipc_get_maxidx(&msg_ids(ns)); |
| 502 | + up_read(&msg_ids(ns).rwsem); |
| 503 | + if (cmd == MSG_INFO) { |
| 504 | + msginfo->msgmap = min_t(int, |
| 505 | + percpu_counter_sum(&ns->percpu_msg_hdrs), |
| 506 | + INT_MAX); |
| 507 | + msginfo->msgtql = min_t(int, |
| 508 | + percpu_counter_sum(&ns->percpu_msg_bytes), |
| 509 | + INT_MAX); |
502 | 510 | } else { |
503 | 511 | msginfo->msgmap = MSGMAP; |
504 | 512 | msginfo->msgpool = MSGPOOL; |
505 | 513 | msginfo->msgtql = MSGTQL; |
506 | 514 | } |
507 | | - max_idx = ipc_get_maxidx(&msg_ids(ns)); |
508 | | - up_read(&msg_ids(ns).rwsem); |
509 | 515 | return (max_idx < 0) ? 0 : max_idx; |
510 | 516 | } |
511 | 517 |
|
@@ -935,8 +941,8 @@ static long do_msgsnd(int msqid, long mtype, void __user *mtext, |
935 | 941 | list_add_tail(&msg->m_list, &msq->q_messages); |
936 | 942 | msq->q_cbytes += msgsz; |
937 | 943 | msq->q_qnum++; |
938 | | - atomic_add(msgsz, &ns->msg_bytes); |
939 | | - atomic_inc(&ns->msg_hdrs); |
| 944 | + percpu_counter_add_local(&ns->percpu_msg_bytes, msgsz); |
| 945 | + percpu_counter_add_local(&ns->percpu_msg_hdrs, 1); |
940 | 946 | } |
941 | 947 |
|
942 | 948 | err = 0; |
@@ -1159,8 +1165,8 @@ static long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, in |
1159 | 1165 | msq->q_rtime = ktime_get_real_seconds(); |
1160 | 1166 | ipc_update_pid(&msq->q_lrpid, task_tgid(current)); |
1161 | 1167 | msq->q_cbytes -= msg->m_ts; |
1162 | | - atomic_sub(msg->m_ts, &ns->msg_bytes); |
1163 | | - atomic_dec(&ns->msg_hdrs); |
| 1168 | + percpu_counter_sub_local(&ns->percpu_msg_bytes, msg->m_ts); |
| 1169 | + percpu_counter_sub_local(&ns->percpu_msg_hdrs, 1); |
1164 | 1170 | ss_wakeup(msq, &wake_q, false); |
1165 | 1171 |
|
1166 | 1172 | goto out_unlock0; |
@@ -1297,20 +1303,34 @@ COMPAT_SYSCALL_DEFINE5(msgrcv, int, msqid, compat_uptr_t, msgp, |
1297 | 1303 | } |
1298 | 1304 | #endif |
1299 | 1305 |
|
1300 | | -void msg_init_ns(struct ipc_namespace *ns) |
| 1306 | +int msg_init_ns(struct ipc_namespace *ns) |
1301 | 1307 | { |
| 1308 | + int ret; |
| 1309 | + |
1302 | 1310 | ns->msg_ctlmax = MSGMAX; |
1303 | 1311 | ns->msg_ctlmnb = MSGMNB; |
1304 | 1312 | ns->msg_ctlmni = MSGMNI; |
1305 | 1313 |
|
1306 | | - atomic_set(&ns->msg_bytes, 0); |
1307 | | - atomic_set(&ns->msg_hdrs, 0); |
| 1314 | + ret = percpu_counter_init(&ns->percpu_msg_bytes, 0, GFP_KERNEL); |
| 1315 | + if (ret) |
| 1316 | + goto fail_msg_bytes; |
| 1317 | + ret = percpu_counter_init(&ns->percpu_msg_hdrs, 0, GFP_KERNEL); |
| 1318 | + if (ret) |
| 1319 | + goto fail_msg_hdrs; |
1308 | 1320 | ipc_init_ids(&ns->ids[IPC_MSG_IDS]); |
| 1321 | + return 0; |
| 1322 | + |
| 1323 | +fail_msg_hdrs: |
| 1324 | + percpu_counter_destroy(&ns->percpu_msg_bytes); |
| 1325 | +fail_msg_bytes: |
| 1326 | + return ret; |
1309 | 1327 | } |
1310 | 1328 |
|
1311 | 1329 | #ifdef CONFIG_IPC_NS |
1312 | 1330 | void msg_exit_ns(struct ipc_namespace *ns) |
1313 | 1331 | { |
| 1332 | + percpu_counter_destroy(&ns->percpu_msg_bytes); |
| 1333 | + percpu_counter_destroy(&ns->percpu_msg_hdrs); |
1314 | 1334 | free_ipcs(ns, &msg_ids(ns), freeque); |
1315 | 1335 | idr_destroy(&ns->ids[IPC_MSG_IDS].ipcs_idr); |
1316 | 1336 | rhashtable_destroy(&ns->ids[IPC_MSG_IDS].key_ht); |
|
0 commit comments