Merge tag 'for-linus-6.1-rc2-tag' of git://git.kernel.org/pub/scm/linux/kernel/git...
[platform/kernel/linux-rpi.git] / ipc / msg.c
index a0d0577..e4e0990 100644 (file)
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -39,6 +39,7 @@
 #include <linux/nsproxy.h>
 #include <linux/ipc_namespace.h>
 #include <linux/rhashtable.h>
+#include <linux/percpu_counter.h>
 
 #include <asm/current.h>
 #include <linux/uaccess.h>
@@ -285,10 +286,10 @@ static void freeque(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
        rcu_read_unlock();
 
        list_for_each_entry_safe(msg, t, &msq->q_messages, m_list) {
-               atomic_dec(&ns->msg_hdrs);
+               percpu_counter_sub_local(&ns->percpu_msg_hdrs, 1);
                free_msg(msg);
        }
-       atomic_sub(msq->q_cbytes, &ns->msg_bytes);
+       percpu_counter_sub_local(&ns->percpu_msg_bytes, msq->q_cbytes);
        ipc_update_pid(&msq->q_lspid, NULL);
        ipc_update_pid(&msq->q_lrpid, NULL);
        ipc_rcu_putref(&msq->q_perm, msg_rcu_free);
@@ -495,17 +496,22 @@ static int msgctl_info(struct ipc_namespace *ns, int msqid,
        msginfo->msgssz = MSGSSZ;
        msginfo->msgseg = MSGSEG;
        down_read(&msg_ids(ns).rwsem);
-       if (cmd == MSG_INFO) {
+       if (cmd == MSG_INFO)
                msginfo->msgpool = msg_ids(ns).in_use;
-               msginfo->msgmap = atomic_read(&ns->msg_hdrs);
-               msginfo->msgtql = atomic_read(&ns->msg_bytes);
+       max_idx = ipc_get_maxidx(&msg_ids(ns));
+       up_read(&msg_ids(ns).rwsem);
+       if (cmd == MSG_INFO) {
+               msginfo->msgmap = min_t(int,
+                                    percpu_counter_sum(&ns->percpu_msg_hdrs),
+                                    INT_MAX);
+               msginfo->msgtql = min_t(int,
+                                    percpu_counter_sum(&ns->percpu_msg_bytes),
+                                    INT_MAX);
        } else {
                msginfo->msgmap = MSGMAP;
                msginfo->msgpool = MSGPOOL;
                msginfo->msgtql = MSGTQL;
        }
-       max_idx = ipc_get_maxidx(&msg_ids(ns));
-       up_read(&msg_ids(ns).rwsem);
        return (max_idx < 0) ? 0 : max_idx;
 }
 
@@ -935,8 +941,8 @@ static long do_msgsnd(int msqid, long mtype, void __user *mtext,
                list_add_tail(&msg->m_list, &msq->q_messages);
                msq->q_cbytes += msgsz;
                msq->q_qnum++;
-               atomic_add(msgsz, &ns->msg_bytes);
-               atomic_inc(&ns->msg_hdrs);
+               percpu_counter_add_local(&ns->percpu_msg_bytes, msgsz);
+               percpu_counter_add_local(&ns->percpu_msg_hdrs, 1);
        }
 
        err = 0;
@@ -1159,8 +1165,8 @@ static long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, in
                        msq->q_rtime = ktime_get_real_seconds();
                        ipc_update_pid(&msq->q_lrpid, task_tgid(current));
                        msq->q_cbytes -= msg->m_ts;
-                       atomic_sub(msg->m_ts, &ns->msg_bytes);
-                       atomic_dec(&ns->msg_hdrs);
+                       percpu_counter_sub_local(&ns->percpu_msg_bytes, msg->m_ts);
+                       percpu_counter_sub_local(&ns->percpu_msg_hdrs, 1);
                        ss_wakeup(msq, &wake_q, false);
 
                        goto out_unlock0;
@@ -1297,20 +1303,34 @@ COMPAT_SYSCALL_DEFINE5(msgrcv, int, msqid, compat_uptr_t, msgp,
 }
 #endif
 
-void msg_init_ns(struct ipc_namespace *ns)
+int msg_init_ns(struct ipc_namespace *ns)
 {
+       int ret;
+
        ns->msg_ctlmax = MSGMAX;
        ns->msg_ctlmnb = MSGMNB;
        ns->msg_ctlmni = MSGMNI;
 
-       atomic_set(&ns->msg_bytes, 0);
-       atomic_set(&ns->msg_hdrs, 0);
+       ret = percpu_counter_init(&ns->percpu_msg_bytes, 0, GFP_KERNEL);
+       if (ret)
+               goto fail_msg_bytes;
+       ret = percpu_counter_init(&ns->percpu_msg_hdrs, 0, GFP_KERNEL);
+       if (ret)
+               goto fail_msg_hdrs;
        ipc_init_ids(&ns->ids[IPC_MSG_IDS]);
+       return 0;
+
+fail_msg_hdrs:
+       percpu_counter_destroy(&ns->percpu_msg_bytes);
+fail_msg_bytes:
+       return ret;
 }
 
 #ifdef CONFIG_IPC_NS
 void msg_exit_ns(struct ipc_namespace *ns)
 {
+       percpu_counter_destroy(&ns->percpu_msg_bytes);
+       percpu_counter_destroy(&ns->percpu_msg_hdrs);
        free_ipcs(ns, &msg_ids(ns), freeque);
        idr_destroy(&ns->ids[IPC_MSG_IDS].ipcs_idr);
        rhashtable_destroy(&ns->ids[IPC_MSG_IDS].key_ht);