aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2018-03-23 01:29:57 -0400
committerEric W. Biederman <ebiederm@xmission.com>2018-03-27 16:53:09 -0400
commit98f929b1bd4d0b7c7a77d0d9776d1b924db2e454 (patch)
tree9cfeab6782aea7b92f858b5e3e595b75fe22bfa3
parent03f1fc09180b345582889a344b012d069b3a6dbe (diff)
ipc/shm: Fix shmctl(..., IPC_STAT, ...) between pid namespaces.
Today shm_cpid and shm_lpid are remembered in the pid namespace of the creator and the processes that last touched a sysvipc shared memory segment. If you have processes in multiple pid namespaces that is just wrong, and I don't know how this has been over-looked for so long. As only creation and shared memory attach and shared memory detach update the pids I do not expect there to be a repeat of the issues when struct pid was attached to each af_unix skb, which in some notable cases cut the performance in half. The problem was threads of the same process updating same struct pid from different cpus causing the cache line to be highly contended and bounce between cpus. As creation, attach, and detach are expected to be rare operations for sysvipc shared memory segments I do not expect that kind of cache line ping pong to cause probems. In addition because the pid is at a fixed location in the structure instead of being dynamic on a skb, the reference count of the pid does not need to be updated on each operation if the pid is the same. This ability to simply skip the pid reference count changes if the pid is unchanging further reduces the likelihood of the a cache line holding a pid reference count ping-ponging between cpus. Fixes: b488893a390e ("pid namespaces: changes to show virtual ids to user") Reviewed-by: Nagarathnam Muthusamy <nagarathnam.muthusamy@oracle.com> Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
-rw-r--r--ipc/shm.c25
1 files changed, 15 insertions, 10 deletions
diff --git a/ipc/shm.c b/ipc/shm.c
index 0565669ebe5c..932b7e411c6c 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -57,8 +57,8 @@ struct shmid_kernel /* private to the kernel */
57 time64_t shm_atim; 57 time64_t shm_atim;
58 time64_t shm_dtim; 58 time64_t shm_dtim;
59 time64_t shm_ctim; 59 time64_t shm_ctim;
60 pid_t shm_cprid; 60 struct pid *shm_cprid;
61 pid_t shm_lprid; 61 struct pid *shm_lprid;
62 struct user_struct *mlock_user; 62 struct user_struct *mlock_user;
63 63
64 /* The task created the shm object. NULL if the task is dead. */ 64 /* The task created the shm object. NULL if the task is dead. */
@@ -226,7 +226,7 @@ static int __shm_open(struct vm_area_struct *vma)
226 return PTR_ERR(shp); 226 return PTR_ERR(shp);
227 227
228 shp->shm_atim = ktime_get_real_seconds(); 228 shp->shm_atim = ktime_get_real_seconds();
229 shp->shm_lprid = task_tgid_vnr(current); 229 ipc_update_pid(&shp->shm_lprid, task_tgid(current));
230 shp->shm_nattch++; 230 shp->shm_nattch++;
231 shm_unlock(shp); 231 shm_unlock(shp);
232 return 0; 232 return 0;
@@ -267,6 +267,8 @@ static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp)
267 user_shm_unlock(i_size_read(file_inode(shm_file)), 267 user_shm_unlock(i_size_read(file_inode(shm_file)),
268 shp->mlock_user); 268 shp->mlock_user);
269 fput(shm_file); 269 fput(shm_file);
270 ipc_update_pid(&shp->shm_cprid, NULL);
271 ipc_update_pid(&shp->shm_lprid, NULL);
270 ipc_rcu_putref(&shp->shm_perm, shm_rcu_free); 272 ipc_rcu_putref(&shp->shm_perm, shm_rcu_free);
271} 273}
272 274
@@ -311,7 +313,7 @@ static void shm_close(struct vm_area_struct *vma)
311 if (WARN_ON_ONCE(IS_ERR(shp))) 313 if (WARN_ON_ONCE(IS_ERR(shp)))
312 goto done; /* no-op */ 314 goto done; /* no-op */
313 315
314 shp->shm_lprid = task_tgid_vnr(current); 316 ipc_update_pid(&shp->shm_lprid, task_tgid(current));
315 shp->shm_dtim = ktime_get_real_seconds(); 317 shp->shm_dtim = ktime_get_real_seconds();
316 shp->shm_nattch--; 318 shp->shm_nattch--;
317 if (shm_may_destroy(ns, shp)) 319 if (shm_may_destroy(ns, shp))
@@ -614,8 +616,8 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
614 if (IS_ERR(file)) 616 if (IS_ERR(file))
615 goto no_file; 617 goto no_file;
616 618
617 shp->shm_cprid = task_tgid_vnr(current); 619 shp->shm_cprid = get_pid(task_tgid(current));
618 shp->shm_lprid = 0; 620 shp->shm_lprid = NULL;
619 shp->shm_atim = shp->shm_dtim = 0; 621 shp->shm_atim = shp->shm_dtim = 0;
620 shp->shm_ctim = ktime_get_real_seconds(); 622 shp->shm_ctim = ktime_get_real_seconds();
621 shp->shm_segsz = size; 623 shp->shm_segsz = size;
@@ -648,6 +650,8 @@ no_id:
648 user_shm_unlock(size, shp->mlock_user); 650 user_shm_unlock(size, shp->mlock_user);
649 fput(file); 651 fput(file);
650no_file: 652no_file:
653 ipc_update_pid(&shp->shm_cprid, NULL);
654 ipc_update_pid(&shp->shm_lprid, NULL);
651 call_rcu(&shp->shm_perm.rcu, shm_rcu_free); 655 call_rcu(&shp->shm_perm.rcu, shm_rcu_free);
652 return error; 656 return error;
653} 657}
@@ -970,8 +974,8 @@ static int shmctl_stat(struct ipc_namespace *ns, int shmid,
970 tbuf->shm_atime = shp->shm_atim; 974 tbuf->shm_atime = shp->shm_atim;
971 tbuf->shm_dtime = shp->shm_dtim; 975 tbuf->shm_dtime = shp->shm_dtim;
972 tbuf->shm_ctime = shp->shm_ctim; 976 tbuf->shm_ctime = shp->shm_ctim;
973 tbuf->shm_cpid = shp->shm_cprid; 977 tbuf->shm_cpid = pid_vnr(shp->shm_cprid);
974 tbuf->shm_lpid = shp->shm_lprid; 978 tbuf->shm_lpid = pid_vnr(shp->shm_lprid);
975 tbuf->shm_nattch = shp->shm_nattch; 979 tbuf->shm_nattch = shp->shm_nattch;
976 980
977 ipc_unlock_object(&shp->shm_perm); 981 ipc_unlock_object(&shp->shm_perm);
@@ -1605,6 +1609,7 @@ SYSCALL_DEFINE1(shmdt, char __user *, shmaddr)
1605#ifdef CONFIG_PROC_FS 1609#ifdef CONFIG_PROC_FS
1606static int sysvipc_shm_proc_show(struct seq_file *s, void *it) 1610static int sysvipc_shm_proc_show(struct seq_file *s, void *it)
1607{ 1611{
1612 struct pid_namespace *pid_ns = ipc_seq_pid_ns(s);
1608 struct user_namespace *user_ns = seq_user_ns(s); 1613 struct user_namespace *user_ns = seq_user_ns(s);
1609 struct kern_ipc_perm *ipcp = it; 1614 struct kern_ipc_perm *ipcp = it;
1610 struct shmid_kernel *shp; 1615 struct shmid_kernel *shp;
@@ -1627,8 +1632,8 @@ static int sysvipc_shm_proc_show(struct seq_file *s, void *it)
1627 shp->shm_perm.id, 1632 shp->shm_perm.id,
1628 shp->shm_perm.mode, 1633 shp->shm_perm.mode,
1629 shp->shm_segsz, 1634 shp->shm_segsz,
1630 shp->shm_cprid, 1635 pid_nr_ns(shp->shm_cprid, pid_ns),
1631 shp->shm_lprid, 1636 pid_nr_ns(shp->shm_lprid, pid_ns),
1632 shp->shm_nattch, 1637 shp->shm_nattch,
1633 from_kuid_munged(user_ns, shp->shm_perm.uid), 1638 from_kuid_munged(user_ns, shp->shm_perm.uid),
1634 from_kgid_munged(user_ns, shp->shm_perm.gid), 1639 from_kgid_munged(user_ns, shp->shm_perm.gid),