ipc/sem.c: replace shared sem_otime with per-semaphore value
authorManfred Spraul <manfred@colorfullife.com>
Mon, 8 Jul 2013 23:01:25 +0000 (16:01 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 18 Oct 2013 14:45:47 +0000 (07:45 -0700)
commit d12e1e50e47e0900dbbf52237b7e171f4f15ea1e upstream.

sem_otime contains the time of the last semaphore operation that
completed successfully.  Every operation updates this value, thus access
from multiple cpus can cause thrashing.

Therefore the patch replaces the variable with a per-semaphore variable.
The per-array sem_otime is only calculated when required.

No performance improvement on a single-socket i3 - only important for
larger systems.

Signed-off-by: Manfred Spraul <manfred@colorfullife.com>
Cc: Rik van Riel <riel@redhat.com>
Cc: Davidlohr Bueso <davidlohr.bueso@hp.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
include/linux/sem.h
ipc/sem.c

index 55e17f68d256a116ce782505ac480f8ee5a7c05e..976ce3a19f1b23646c4494029929e538f5e0204b 100644 (file)
@@ -12,7 +12,6 @@ struct task_struct;
 struct sem_array {
        struct kern_ipc_perm    ____cacheline_aligned_in_smp
                                sem_perm;       /* permissions .. see ipc.h */
-       time_t                  sem_otime;      /* last semop time */
        time_t                  sem_ctime;      /* last change time */
        struct sem              *sem_base;      /* ptr to first semaphore in array */
        struct list_head        pending_alter;  /* pending operations */
index 6291257ee0498e9976e1d0bf5bcea250ee95f93d..51352e1bfff912c6b414be3b494995c5e0e2556d 100644 (file)
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -99,6 +99,7 @@ struct sem {
                                        /* that alter the semaphore */
        struct list_head pending_const; /* pending single-sop operations */
                                        /* that do not alter the semaphore*/
+       time_t  sem_otime;      /* candidate for sem_otime */
 } ____cacheline_aligned_in_smp;
 
 /* One queue for each sleeping process in the system. */
@@ -911,8 +912,14 @@ static void do_smart_update(struct sem_array *sma, struct sembuf *sops, int nsop
                        }
                }
        }
-       if (otime)
-               sma->sem_otime = get_seconds();
+       if (otime) {
+               if (sops == NULL) {
+                       sma->sem_base[0].sem_otime = get_seconds();
+               } else {
+                       sma->sem_base[sops[0].sem_num].sem_otime =
+                                                               get_seconds();
+               }
+       }
 }
 
 
@@ -1058,6 +1065,21 @@ static unsigned long copy_semid_to_user(void __user *buf, struct semid64_ds *in,
        }
 }
 
+static time_t get_semotime(struct sem_array *sma)
+{
+       int i;
+       time_t res;
+
+       res = sma->sem_base[0].sem_otime;
+       for (i = 1; i < sma->sem_nsems; i++) {
+               time_t to = sma->sem_base[i].sem_otime;
+
+               if (to > res)
+                       res = to;
+       }
+       return res;
+}
+
 static int semctl_nolock(struct ipc_namespace *ns, int semid,
                         int cmd, int version, void __user *p)
 {
@@ -1131,9 +1153,9 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid,
                        goto out_unlock;
 
                kernel_to_ipc64_perm(&sma->sem_perm, &tbuf.sem_perm);
-               tbuf.sem_otime  = sma->sem_otime;
-               tbuf.sem_ctime  = sma->sem_ctime;
-               tbuf.sem_nsems  = sma->sem_nsems;
+               tbuf.sem_otime = get_semotime(sma);
+               tbuf.sem_ctime = sma->sem_ctime;
+               tbuf.sem_nsems = sma->sem_nsems;
                rcu_read_unlock();
                if (copy_semid_to_user(p, &tbuf, version))
                        return -EFAULT;
@@ -2025,6 +2047,9 @@ static int sysvipc_sem_proc_show(struct seq_file *s, void *it)
 {
        struct user_namespace *user_ns = seq_user_ns(s);
        struct sem_array *sma = it;
+       time_t sem_otime;
+
+       sem_otime = get_semotime(sma);
 
        return seq_printf(s,
                          "%10d %10d  %4o %10u %5u %5u %5u %5u %10lu %10lu\n",
@@ -2036,7 +2061,7 @@ static int sysvipc_sem_proc_show(struct seq_file *s, void *it)
                          from_kgid_munged(user_ns, sma->sem_perm.gid),
                          from_kuid_munged(user_ns, sma->sem_perm.cuid),
                          from_kgid_munged(user_ns, sma->sem_perm.cgid),
-                         sma->sem_otime,
+                         sem_otime,
                          sma->sem_ctime);
 }
 #endif