Skip to content

Commit 98f929b

Browse files
committed
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: b488893 ("pid namespaces: changes to show virtual ids to user") Reviewed-by: Nagarathnam Muthusamy <[email protected]> Signed-off-by: "Eric W. Biederman" <[email protected]>
1 parent 03f1fc0 commit 98f929b

File tree

1 file changed

+15
-10
lines changed

1 file changed

+15
-10
lines changed

ipc/shm.c

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ struct shmid_kernel /* private to the kernel */
5757
time64_t shm_atim;
5858
time64_t shm_dtim;
5959
time64_t shm_ctim;
60-
pid_t shm_cprid;
61-
pid_t shm_lprid;
60+
struct pid *shm_cprid;
61+
struct pid *shm_lprid;
6262
struct user_struct *mlock_user;
6363

6464
/* 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)
226226
return PTR_ERR(shp);
227227

228228
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));
230230
shp->shm_nattch++;
231231
shm_unlock(shp);
232232
return 0;
@@ -267,6 +267,8 @@ static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp)
267267
user_shm_unlock(i_size_read(file_inode(shm_file)),
268268
shp->mlock_user);
269269
fput(shm_file);
270+
ipc_update_pid(&shp->shm_cprid, NULL);
271+
ipc_update_pid(&shp->shm_lprid, NULL);
270272
ipc_rcu_putref(&shp->shm_perm, shm_rcu_free);
271273
}
272274

@@ -311,7 +313,7 @@ static void shm_close(struct vm_area_struct *vma)
311313
if (WARN_ON_ONCE(IS_ERR(shp)))
312314
goto done; /* no-op */
313315

314-
shp->shm_lprid = task_tgid_vnr(current);
316+
ipc_update_pid(&shp->shm_lprid, task_tgid(current));
315317
shp->shm_dtim = ktime_get_real_seconds();
316318
shp->shm_nattch--;
317319
if (shm_may_destroy(ns, shp))
@@ -614,8 +616,8 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
614616
if (IS_ERR(file))
615617
goto no_file;
616618

617-
shp->shm_cprid = task_tgid_vnr(current);
618-
shp->shm_lprid = 0;
619+
shp->shm_cprid = get_pid(task_tgid(current));
620+
shp->shm_lprid = NULL;
619621
shp->shm_atim = shp->shm_dtim = 0;
620622
shp->shm_ctim = ktime_get_real_seconds();
621623
shp->shm_segsz = size;
@@ -648,6 +650,8 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
648650
user_shm_unlock(size, shp->mlock_user);
649651
fput(file);
650652
no_file:
653+
ipc_update_pid(&shp->shm_cprid, NULL);
654+
ipc_update_pid(&shp->shm_lprid, NULL);
651655
call_rcu(&shp->shm_perm.rcu, shm_rcu_free);
652656
return error;
653657
}
@@ -970,8 +974,8 @@ static int shmctl_stat(struct ipc_namespace *ns, int shmid,
970974
tbuf->shm_atime = shp->shm_atim;
971975
tbuf->shm_dtime = shp->shm_dtim;
972976
tbuf->shm_ctime = shp->shm_ctim;
973-
tbuf->shm_cpid = shp->shm_cprid;
974-
tbuf->shm_lpid = shp->shm_lprid;
977+
tbuf->shm_cpid = pid_vnr(shp->shm_cprid);
978+
tbuf->shm_lpid = pid_vnr(shp->shm_lprid);
975979
tbuf->shm_nattch = shp->shm_nattch;
976980

977981
ipc_unlock_object(&shp->shm_perm);
@@ -1605,6 +1609,7 @@ SYSCALL_DEFINE1(shmdt, char __user *, shmaddr)
16051609
#ifdef CONFIG_PROC_FS
16061610
static int sysvipc_shm_proc_show(struct seq_file *s, void *it)
16071611
{
1612+
struct pid_namespace *pid_ns = ipc_seq_pid_ns(s);
16081613
struct user_namespace *user_ns = seq_user_ns(s);
16091614
struct kern_ipc_perm *ipcp = it;
16101615
struct shmid_kernel *shp;
@@ -1627,8 +1632,8 @@ static int sysvipc_shm_proc_show(struct seq_file *s, void *it)
16271632
shp->shm_perm.id,
16281633
shp->shm_perm.mode,
16291634
shp->shm_segsz,
1630-
shp->shm_cprid,
1631-
shp->shm_lprid,
1635+
pid_nr_ns(shp->shm_cprid, pid_ns),
1636+
pid_nr_ns(shp->shm_lprid, pid_ns),
16321637
shp->shm_nattch,
16331638
from_kuid_munged(user_ns, shp->shm_perm.uid),
16341639
from_kgid_munged(user_ns, shp->shm_perm.gid),

0 commit comments

Comments
 (0)