1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (c) International Business Machines Corp., 2001 4f08c3bdfSopenharmony_ci * Copyright (C) 2020 Cyril Hrubis <chrubis@suse.cz> 5f08c3bdfSopenharmony_ci */ 6f08c3bdfSopenharmony_ci 7f08c3bdfSopenharmony_ci/*\ 8f08c3bdfSopenharmony_ci * [Description] 9f08c3bdfSopenharmony_ci * 10f08c3bdfSopenharmony_ci * Verify that shmctl() IPC_STAT and SHM_STAT reports correct data. 11f08c3bdfSopenharmony_ci * 12f08c3bdfSopenharmony_ci * The shm_nattach is excercised by: 13f08c3bdfSopenharmony_ci * 14f08c3bdfSopenharmony_ci * - forking() children that attach and detach SHM 15f08c3bdfSopenharmony_ci * - attaching the SHM before fork and letting the children detach it 16f08c3bdfSopenharmony_ci * 17f08c3bdfSopenharmony_ci * We check that the number shm_nattach is correct after each step we do. 18f08c3bdfSopenharmony_ci */ 19f08c3bdfSopenharmony_ci 20f08c3bdfSopenharmony_ci#define _GNU_SOURCE 21f08c3bdfSopenharmony_ci#include <stdlib.h> 22f08c3bdfSopenharmony_ci#include "tst_test.h" 23f08c3bdfSopenharmony_ci#include "tst_safe_sysv_ipc.h" 24f08c3bdfSopenharmony_ci#include "tst_clocks.h" 25f08c3bdfSopenharmony_ci#include "libnewipc.h" 26f08c3bdfSopenharmony_ci 27f08c3bdfSopenharmony_ci#define NCHILD 20 28f08c3bdfSopenharmony_ci 29f08c3bdfSopenharmony_cistatic pid_t children[NCHILD]; 30f08c3bdfSopenharmony_ci 31f08c3bdfSopenharmony_cistatic int shm_id; 32f08c3bdfSopenharmony_cistatic int shm_idx; 33f08c3bdfSopenharmony_cistatic time_t ctime_min, ctime_max; 34f08c3bdfSopenharmony_ci 35f08c3bdfSopenharmony_cistatic void *addr; 36f08c3bdfSopenharmony_ci 37f08c3bdfSopenharmony_cistatic void attach_child(void) 38f08c3bdfSopenharmony_ci{ 39f08c3bdfSopenharmony_ci pause(); 40f08c3bdfSopenharmony_ci 41f08c3bdfSopenharmony_ci addr = SAFE_SHMAT(shm_id, NULL, 0); 42f08c3bdfSopenharmony_ci 43f08c3bdfSopenharmony_ci pause(); 44f08c3bdfSopenharmony_ci 45f08c3bdfSopenharmony_ci SAFE_SHMDT(addr); 46f08c3bdfSopenharmony_ci 47f08c3bdfSopenharmony_ci pause(); 48f08c3bdfSopenharmony_ci 49f08c3bdfSopenharmony_ci exit(0); 50f08c3bdfSopenharmony_ci} 51f08c3bdfSopenharmony_ci 52f08c3bdfSopenharmony_cistatic void detach_child(void) 53f08c3bdfSopenharmony_ci{ 54f08c3bdfSopenharmony_ci pause(); 55f08c3bdfSopenharmony_ci 56f08c3bdfSopenharmony_ci SAFE_SHMDT(addr); 57f08c3bdfSopenharmony_ci 58f08c3bdfSopenharmony_ci pause(); 59f08c3bdfSopenharmony_ci 60f08c3bdfSopenharmony_ci exit(0); 61f08c3bdfSopenharmony_ci} 62f08c3bdfSopenharmony_ci 63f08c3bdfSopenharmony_cistatic void fork_children(void (*child_func)(void)) 64f08c3bdfSopenharmony_ci{ 65f08c3bdfSopenharmony_ci unsigned int i; 66f08c3bdfSopenharmony_ci 67f08c3bdfSopenharmony_ci for (i = 0; i < NCHILD; i++) { 68f08c3bdfSopenharmony_ci pid_t pid = SAFE_FORK(); 69f08c3bdfSopenharmony_ci 70f08c3bdfSopenharmony_ci if (!pid) 71f08c3bdfSopenharmony_ci child_func(); 72f08c3bdfSopenharmony_ci 73f08c3bdfSopenharmony_ci children[i] = pid; 74f08c3bdfSopenharmony_ci } 75f08c3bdfSopenharmony_ci} 76f08c3bdfSopenharmony_ci 77f08c3bdfSopenharmony_cistatic void wait_for_children(void) 78f08c3bdfSopenharmony_ci{ 79f08c3bdfSopenharmony_ci unsigned int i; 80f08c3bdfSopenharmony_ci 81f08c3bdfSopenharmony_ci for (i = 0; i < NCHILD; i++) 82f08c3bdfSopenharmony_ci TST_PROCESS_STATE_WAIT(children[i], 'S', 0); 83f08c3bdfSopenharmony_ci} 84f08c3bdfSopenharmony_ci 85f08c3bdfSopenharmony_cistatic void signal_children(void) 86f08c3bdfSopenharmony_ci{ 87f08c3bdfSopenharmony_ci unsigned int i; 88f08c3bdfSopenharmony_ci 89f08c3bdfSopenharmony_ci for (i = 0; i < NCHILD; i++) 90f08c3bdfSopenharmony_ci SAFE_KILL(children[i], SIGUSR1); 91f08c3bdfSopenharmony_ci} 92f08c3bdfSopenharmony_ci 93f08c3bdfSopenharmony_cistatic void reap_children(void) 94f08c3bdfSopenharmony_ci{ 95f08c3bdfSopenharmony_ci unsigned int i; 96f08c3bdfSopenharmony_ci 97f08c3bdfSopenharmony_ci for (i = 0; i < NCHILD; i++) 98f08c3bdfSopenharmony_ci SAFE_WAITPID(children[i], NULL, 0); 99f08c3bdfSopenharmony_ci} 100f08c3bdfSopenharmony_ci 101f08c3bdfSopenharmony_cistatic void check_nattch(int exp_nattch, const char *msg) 102f08c3bdfSopenharmony_ci{ 103f08c3bdfSopenharmony_ci struct shmid_ds ds1; 104f08c3bdfSopenharmony_ci struct shmid_ds ds2; 105f08c3bdfSopenharmony_ci 106f08c3bdfSopenharmony_ci SAFE_SHMCTL(shm_id, IPC_STAT, &ds1); 107f08c3bdfSopenharmony_ci SAFE_SHMCTL(shm_idx, SHM_STAT, &ds2); 108f08c3bdfSopenharmony_ci 109f08c3bdfSopenharmony_ci if (ds1.shm_nattch != ds2.shm_nattch) { 110f08c3bdfSopenharmony_ci tst_res(TFAIL, "IPC_STAT nattch=%li SHM_STAT nattch=%li", 111f08c3bdfSopenharmony_ci (long)ds1.shm_nattch, (long)ds2.shm_nattch); 112f08c3bdfSopenharmony_ci return; 113f08c3bdfSopenharmony_ci } 114f08c3bdfSopenharmony_ci 115f08c3bdfSopenharmony_ci if ((int)ds1.shm_nattch == exp_nattch) { 116f08c3bdfSopenharmony_ci tst_res(TPASS, "%s shm_nattch=%i", msg, exp_nattch); 117f08c3bdfSopenharmony_ci return; 118f08c3bdfSopenharmony_ci } 119f08c3bdfSopenharmony_ci 120f08c3bdfSopenharmony_ci tst_res(TFAIL, "%s shm_nattcg=%li expected %i", 121f08c3bdfSopenharmony_ci msg, (long)ds1.shm_nattch, exp_nattch); 122f08c3bdfSopenharmony_ci} 123f08c3bdfSopenharmony_ci 124f08c3bdfSopenharmony_cistatic void verify_shmstat_attach(void) 125f08c3bdfSopenharmony_ci{ 126f08c3bdfSopenharmony_ci fork_children(attach_child); 127f08c3bdfSopenharmony_ci wait_for_children(); 128f08c3bdfSopenharmony_ci 129f08c3bdfSopenharmony_ci check_nattch(0, "before child shmat()"); 130f08c3bdfSopenharmony_ci 131f08c3bdfSopenharmony_ci signal_children(); 132f08c3bdfSopenharmony_ci wait_for_children(); 133f08c3bdfSopenharmony_ci 134f08c3bdfSopenharmony_ci check_nattch(NCHILD, "after child shmat()"); 135f08c3bdfSopenharmony_ci 136f08c3bdfSopenharmony_ci signal_children(); 137f08c3bdfSopenharmony_ci wait_for_children(); 138f08c3bdfSopenharmony_ci 139f08c3bdfSopenharmony_ci check_nattch(0, "after child shmdt()"); 140f08c3bdfSopenharmony_ci 141f08c3bdfSopenharmony_ci signal_children(); 142f08c3bdfSopenharmony_ci reap_children(); 143f08c3bdfSopenharmony_ci} 144f08c3bdfSopenharmony_ci 145f08c3bdfSopenharmony_cistatic void verify_shmstat_inherit(void) 146f08c3bdfSopenharmony_ci{ 147f08c3bdfSopenharmony_ci addr = SAFE_SHMAT(shm_id, NULL, 0); 148f08c3bdfSopenharmony_ci 149f08c3bdfSopenharmony_ci fork_children(detach_child); 150f08c3bdfSopenharmony_ci wait_for_children(); 151f08c3bdfSopenharmony_ci 152f08c3bdfSopenharmony_ci check_nattch(NCHILD+1, "inherited after fork()"); 153f08c3bdfSopenharmony_ci 154f08c3bdfSopenharmony_ci signal_children(); 155f08c3bdfSopenharmony_ci wait_for_children(); 156f08c3bdfSopenharmony_ci 157f08c3bdfSopenharmony_ci check_nattch(1, "after child shmdt()"); 158f08c3bdfSopenharmony_ci 159f08c3bdfSopenharmony_ci SAFE_SHMDT(addr); 160f08c3bdfSopenharmony_ci 161f08c3bdfSopenharmony_ci check_nattch(0, "after parent shmdt()"); 162f08c3bdfSopenharmony_ci 163f08c3bdfSopenharmony_ci signal_children(); 164f08c3bdfSopenharmony_ci reap_children(); 165f08c3bdfSopenharmony_ci} 166f08c3bdfSopenharmony_ci 167f08c3bdfSopenharmony_cistatic void check_ds(struct shmid_ds *ds, const char *desc) 168f08c3bdfSopenharmony_ci{ 169f08c3bdfSopenharmony_ci pid_t pid = getpid(); 170f08c3bdfSopenharmony_ci 171f08c3bdfSopenharmony_ci if (ds->shm_segsz != SHM_SIZE) { 172f08c3bdfSopenharmony_ci tst_res(TFAIL, "%s: shm_segsz=%zu, expected %i", 173f08c3bdfSopenharmony_ci desc, ds->shm_segsz, SHM_SIZE); 174f08c3bdfSopenharmony_ci } else { 175f08c3bdfSopenharmony_ci tst_res(TPASS, "%s: shm_segsz=%i", desc, SHM_SIZE); 176f08c3bdfSopenharmony_ci } 177f08c3bdfSopenharmony_ci 178f08c3bdfSopenharmony_ci if (ds->shm_cpid != pid) { 179f08c3bdfSopenharmony_ci tst_res(TFAIL, "%s: shm_cpid=%i, expected %i", 180f08c3bdfSopenharmony_ci desc, ds->shm_cpid, pid); 181f08c3bdfSopenharmony_ci } else { 182f08c3bdfSopenharmony_ci tst_res(TPASS, "%s: shm_cpid=%i", desc, pid); 183f08c3bdfSopenharmony_ci } 184f08c3bdfSopenharmony_ci 185f08c3bdfSopenharmony_ci if (ds->shm_ctime < ctime_min || ds->shm_ctime > ctime_max) { 186f08c3bdfSopenharmony_ci tst_res(TFAIL, "%s: shm_ctime=%li, expected <%li,%li>", 187f08c3bdfSopenharmony_ci desc, ds->shm_ctime, ctime_min, ctime_max); 188f08c3bdfSopenharmony_ci } else { 189f08c3bdfSopenharmony_ci tst_res(TPASS, "%s: shm_ctime=%li in range <%li,%li>", 190f08c3bdfSopenharmony_ci desc, ds->shm_ctime, ctime_min, ctime_max); 191f08c3bdfSopenharmony_ci } 192f08c3bdfSopenharmony_ci} 193f08c3bdfSopenharmony_ci 194f08c3bdfSopenharmony_cistatic void shmstat_basic_check(void) 195f08c3bdfSopenharmony_ci{ 196f08c3bdfSopenharmony_ci struct shmid_ds ds; 197f08c3bdfSopenharmony_ci 198f08c3bdfSopenharmony_ci memset(&ds, 0, sizeof(ds)); 199f08c3bdfSopenharmony_ci SAFE_SHMCTL(shm_id, IPC_STAT, &ds); 200f08c3bdfSopenharmony_ci 201f08c3bdfSopenharmony_ci check_ds(&ds, "IPC_STAT"); 202f08c3bdfSopenharmony_ci 203f08c3bdfSopenharmony_ci memset(&ds, 0, sizeof(ds)); 204f08c3bdfSopenharmony_ci SAFE_SHMCTL(shm_idx, SHM_STAT, &ds); 205f08c3bdfSopenharmony_ci 206f08c3bdfSopenharmony_ci check_ds(&ds, "SHM_STAT"); 207f08c3bdfSopenharmony_ci} 208f08c3bdfSopenharmony_ci 209f08c3bdfSopenharmony_cistatic struct tcase { 210f08c3bdfSopenharmony_ci void (*func)(void); 211f08c3bdfSopenharmony_ci const char *desc; 212f08c3bdfSopenharmony_ci} tcases[] = { 213f08c3bdfSopenharmony_ci {shmstat_basic_check, "Basic checks"}, 214f08c3bdfSopenharmony_ci {verify_shmstat_attach, "Children attach SHM"}, 215f08c3bdfSopenharmony_ci {verify_shmstat_inherit, "Chidlren inherit SHM"}, 216f08c3bdfSopenharmony_ci}; 217f08c3bdfSopenharmony_ci 218f08c3bdfSopenharmony_cistatic void verify_shmstat(unsigned int n) 219f08c3bdfSopenharmony_ci{ 220f08c3bdfSopenharmony_ci tst_res(TINFO, "%s", tcases[n].desc); 221f08c3bdfSopenharmony_ci tcases[n].func(); 222f08c3bdfSopenharmony_ci} 223f08c3bdfSopenharmony_ci 224f08c3bdfSopenharmony_cistatic void dummy_sighandler(int sig) 225f08c3bdfSopenharmony_ci{ 226f08c3bdfSopenharmony_ci (void)sig; 227f08c3bdfSopenharmony_ci} 228f08c3bdfSopenharmony_ci 229f08c3bdfSopenharmony_cistatic int get_shm_idx_from_id(int shm_id) 230f08c3bdfSopenharmony_ci{ 231f08c3bdfSopenharmony_ci struct shm_info dummy; 232f08c3bdfSopenharmony_ci struct shmid_ds dummy_ds; 233f08c3bdfSopenharmony_ci int max_idx, i; 234f08c3bdfSopenharmony_ci 235f08c3bdfSopenharmony_ci max_idx = SAFE_SHMCTL(shm_id, SHM_INFO, (void *)&dummy); 236f08c3bdfSopenharmony_ci 237f08c3bdfSopenharmony_ci for (i = 0; i <= max_idx; i++) { 238f08c3bdfSopenharmony_ci if (shmctl(i, SHM_STAT, &dummy_ds) == shm_id) 239f08c3bdfSopenharmony_ci return i; 240f08c3bdfSopenharmony_ci } 241f08c3bdfSopenharmony_ci 242f08c3bdfSopenharmony_ci return -1; 243f08c3bdfSopenharmony_ci} 244f08c3bdfSopenharmony_ci 245f08c3bdfSopenharmony_cistatic void setup(void) 246f08c3bdfSopenharmony_ci{ 247f08c3bdfSopenharmony_ci ctime_min = tst_get_fs_timestamp(); 248f08c3bdfSopenharmony_ci shm_id = SAFE_SHMGET(IPC_PRIVATE, SHM_SIZE, IPC_CREAT | SHM_RW); 249f08c3bdfSopenharmony_ci ctime_max = tst_get_fs_timestamp(); 250f08c3bdfSopenharmony_ci 251f08c3bdfSopenharmony_ci shm_idx = get_shm_idx_from_id(shm_id); 252f08c3bdfSopenharmony_ci 253f08c3bdfSopenharmony_ci if (shm_idx < 0) 254f08c3bdfSopenharmony_ci tst_brk(TBROK, "Failed to get shm_id to idx mapping"); 255f08c3bdfSopenharmony_ci 256f08c3bdfSopenharmony_ci tst_res(TINFO, "shm_id=%i maps to kernel index=%i", shm_id, shm_idx); 257f08c3bdfSopenharmony_ci 258f08c3bdfSopenharmony_ci SAFE_SIGNAL(SIGUSR1, dummy_sighandler); 259f08c3bdfSopenharmony_ci} 260f08c3bdfSopenharmony_ci 261f08c3bdfSopenharmony_cistatic void cleanup(void) 262f08c3bdfSopenharmony_ci{ 263f08c3bdfSopenharmony_ci if (shm_id >= 0) 264f08c3bdfSopenharmony_ci SAFE_SHMCTL(shm_id, IPC_RMID, NULL); 265f08c3bdfSopenharmony_ci} 266f08c3bdfSopenharmony_ci 267f08c3bdfSopenharmony_cistatic struct tst_test test = { 268f08c3bdfSopenharmony_ci .setup = setup, 269f08c3bdfSopenharmony_ci .cleanup = cleanup, 270f08c3bdfSopenharmony_ci .forks_child = 1, 271f08c3bdfSopenharmony_ci .test = verify_shmstat, 272f08c3bdfSopenharmony_ci .tcnt = ARRAY_SIZE(tcases), 273f08c3bdfSopenharmony_ci}; 274