1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (c) International Business Machines Corp., 2004 4f08c3bdfSopenharmony_ci * Copyright (c) Linux Test Project, 2004-2020 5f08c3bdfSopenharmony_ci */ 6f08c3bdfSopenharmony_ci 7f08c3bdfSopenharmony_ci/* 8f08c3bdfSopenharmony_ci * DESCRIPTION 9f08c3bdfSopenharmony_ci * hugeshmctl01 - test the IPC_STAT, IPC_SET and IPC_RMID commands as 10f08c3bdfSopenharmony_ci * they are used with shmctl() 11f08c3bdfSopenharmony_ci * 12f08c3bdfSopenharmony_ci * ALGORITHM 13f08c3bdfSopenharmony_ci * loop if that option was specified 14f08c3bdfSopenharmony_ci * create a large shared memory segment with read and write permission 15f08c3bdfSopenharmony_ci * set up any test case specific conditions 16f08c3bdfSopenharmony_ci * call shmctl() using the TEST macro 17f08c3bdfSopenharmony_ci * check the return code 18f08c3bdfSopenharmony_ci * if failure, issue a FAIL message. 19f08c3bdfSopenharmony_ci * otherwise, 20f08c3bdfSopenharmony_ci * if doing functionality testing 21f08c3bdfSopenharmony_ci * call the correct test function 22f08c3bdfSopenharmony_ci * if the conditions are correct, 23f08c3bdfSopenharmony_ci * issue a PASS message 24f08c3bdfSopenharmony_ci * otherwise 25f08c3bdfSopenharmony_ci * issue a FAIL message 26f08c3bdfSopenharmony_ci * otherwise 27f08c3bdfSopenharmony_ci * issue a PASS message 28f08c3bdfSopenharmony_ci * call cleanup 29f08c3bdfSopenharmony_ci * 30f08c3bdfSopenharmony_ci * HISTORY 31f08c3bdfSopenharmony_ci * 03/2001 - Written by Wayne Boyer 32f08c3bdfSopenharmony_ci * 04/2004 - Updated by Robbie Williamson 33f08c3bdfSopenharmony_ci */ 34f08c3bdfSopenharmony_ci 35f08c3bdfSopenharmony_ci#include <limits.h> 36f08c3bdfSopenharmony_ci#include "hugetlb.h" 37f08c3bdfSopenharmony_ci 38f08c3bdfSopenharmony_ci#define N_ATTACH 4U 39f08c3bdfSopenharmony_ci#define NEWMODE 0066 40f08c3bdfSopenharmony_ci 41f08c3bdfSopenharmony_cistatic size_t shm_size; 42f08c3bdfSopenharmony_cistatic int shm_id_1 = -1; 43f08c3bdfSopenharmony_cistatic struct shmid_ds buf; 44f08c3bdfSopenharmony_cistatic time_t save_time; 45f08c3bdfSopenharmony_cistatic void *attach_to_parent; 46f08c3bdfSopenharmony_ci 47f08c3bdfSopenharmony_cistatic void stat_setup_1(void); 48f08c3bdfSopenharmony_cistatic void stat_cleanup(void); 49f08c3bdfSopenharmony_cistatic void stat_setup_2(void); 50f08c3bdfSopenharmony_cistatic void set_setup(void); 51f08c3bdfSopenharmony_cistatic void func_stat(void); 52f08c3bdfSopenharmony_cistatic void func_set(void); 53f08c3bdfSopenharmony_cistatic void func_rmid(void); 54f08c3bdfSopenharmony_cistatic void *set_shmat(void); 55f08c3bdfSopenharmony_ci 56f08c3bdfSopenharmony_cistatic struct tcase { 57f08c3bdfSopenharmony_ci int cmd; 58f08c3bdfSopenharmony_ci void (*func_test)(void); 59f08c3bdfSopenharmony_ci void (*func_setup)(void); 60f08c3bdfSopenharmony_ci} tcases[] = { 61f08c3bdfSopenharmony_ci {IPC_STAT, func_stat, stat_setup_1}, 62f08c3bdfSopenharmony_ci {IPC_STAT, func_stat, stat_setup_2}, 63f08c3bdfSopenharmony_ci {IPC_SET, func_set, set_setup}, 64f08c3bdfSopenharmony_ci {IPC_RMID, func_rmid, NULL} 65f08c3bdfSopenharmony_ci}; 66f08c3bdfSopenharmony_ci 67f08c3bdfSopenharmony_cistatic void test_hugeshmctl(unsigned int i) 68f08c3bdfSopenharmony_ci{ 69f08c3bdfSopenharmony_ci /* 70f08c3bdfSopenharmony_ci * Create a shared memory segment with read and write 71f08c3bdfSopenharmony_ci * permissions. Do this here instead of in setup() 72f08c3bdfSopenharmony_ci * so that looping (-i) will work correctly. 73f08c3bdfSopenharmony_ci */ 74f08c3bdfSopenharmony_ci if (i == 0) 75f08c3bdfSopenharmony_ci shm_id_1 = shmget(shmkey, shm_size, 76f08c3bdfSopenharmony_ci SHM_HUGETLB | IPC_CREAT | IPC_EXCL | SHM_RW); 77f08c3bdfSopenharmony_ci if (shm_id_1 == -1) 78f08c3bdfSopenharmony_ci tst_brk(TBROK | TERRNO, "shmget #main"); 79f08c3bdfSopenharmony_ci 80f08c3bdfSopenharmony_ci if (tcases[i].func_setup != NULL) 81f08c3bdfSopenharmony_ci (*tcases[i].func_setup) (); 82f08c3bdfSopenharmony_ci 83f08c3bdfSopenharmony_ci if (shmctl(shm_id_1, tcases[i].cmd, &buf) == -1) { 84f08c3bdfSopenharmony_ci tst_res(TFAIL | TERRNO, "shmctl #main"); 85f08c3bdfSopenharmony_ci return; 86f08c3bdfSopenharmony_ci } 87f08c3bdfSopenharmony_ci (*tcases[i].func_test)(); 88f08c3bdfSopenharmony_ci} 89f08c3bdfSopenharmony_ci 90f08c3bdfSopenharmony_ci/* 91f08c3bdfSopenharmony_ci * set_shmat() - Attach the shared memory and return the pointer. 92f08c3bdfSopenharmony_ci */ 93f08c3bdfSopenharmony_cistatic void *set_shmat(void) 94f08c3bdfSopenharmony_ci{ 95f08c3bdfSopenharmony_ci void *rval; 96f08c3bdfSopenharmony_ci 97f08c3bdfSopenharmony_ci rval = shmat(shm_id_1, 0, 0); 98f08c3bdfSopenharmony_ci if (rval == (void *)-1) 99f08c3bdfSopenharmony_ci tst_brk(TBROK | TERRNO, "set shmat"); 100f08c3bdfSopenharmony_ci 101f08c3bdfSopenharmony_ci return rval; 102f08c3bdfSopenharmony_ci} 103f08c3bdfSopenharmony_ci 104f08c3bdfSopenharmony_ci/* 105f08c3bdfSopenharmony_ci * stat_setup_2() - Set up for the IPC_STAT command with shmctl(). 106f08c3bdfSopenharmony_ci * Attach the shared memory to parent process and 107f08c3bdfSopenharmony_ci * some children will inherit the shared memory. 108f08c3bdfSopenharmony_ci */ 109f08c3bdfSopenharmony_cistatic void stat_setup_2(void) 110f08c3bdfSopenharmony_ci{ 111f08c3bdfSopenharmony_ci if (!attach_to_parent) 112f08c3bdfSopenharmony_ci attach_to_parent = set_shmat(); 113f08c3bdfSopenharmony_ci stat_setup_1(); 114f08c3bdfSopenharmony_ci} 115f08c3bdfSopenharmony_ci 116f08c3bdfSopenharmony_ci/* 117f08c3bdfSopenharmony_ci * stat_setup_1() - Set up for the IPC_STAT command with shmctl(). 118f08c3bdfSopenharmony_ci * some children will inherit or attatch the shared memory. 119f08c3bdfSopenharmony_ci * It deponds on whther we attach the shared memory 120f08c3bdfSopenharmony_ci * to parent process. 121f08c3bdfSopenharmony_ci */ 122f08c3bdfSopenharmony_cistatic void stat_setup_1(void) 123f08c3bdfSopenharmony_ci{ 124f08c3bdfSopenharmony_ci unsigned int i; 125f08c3bdfSopenharmony_ci void *test; 126f08c3bdfSopenharmony_ci pid_t pid; 127f08c3bdfSopenharmony_ci 128f08c3bdfSopenharmony_ci for (i = 0; i < N_ATTACH; i++) { 129f08c3bdfSopenharmony_ci switch (pid = SAFE_FORK()) { 130f08c3bdfSopenharmony_ci case 0: 131f08c3bdfSopenharmony_ci test = (attach_to_parent == NULL) ? set_shmat() : attach_to_parent; 132f08c3bdfSopenharmony_ci /* do an assignement for fun */ 133f08c3bdfSopenharmony_ci *(int *)test = i; 134f08c3bdfSopenharmony_ci 135f08c3bdfSopenharmony_ci TST_CHECKPOINT_WAKE(0); 136f08c3bdfSopenharmony_ci 137f08c3bdfSopenharmony_ci TST_CHECKPOINT_WAIT(1); 138f08c3bdfSopenharmony_ci 139f08c3bdfSopenharmony_ci /* now we're back - detach the memory and exit */ 140f08c3bdfSopenharmony_ci if (shmdt(test) == -1) 141f08c3bdfSopenharmony_ci tst_brk(TBROK | TERRNO, 142f08c3bdfSopenharmony_ci "shmdt in this function broke"); 143f08c3bdfSopenharmony_ci 144f08c3bdfSopenharmony_ci exit(0); 145f08c3bdfSopenharmony_ci default: 146f08c3bdfSopenharmony_ci TST_CHECKPOINT_WAIT(0); 147f08c3bdfSopenharmony_ci } 148f08c3bdfSopenharmony_ci } 149f08c3bdfSopenharmony_ci} 150f08c3bdfSopenharmony_ci 151f08c3bdfSopenharmony_ci 152f08c3bdfSopenharmony_ci/* 153f08c3bdfSopenharmony_ci * func_stat() - check the functionality of the IPC_STAT command with shmctl() 154f08c3bdfSopenharmony_ci * by looking at the pid of the creator, the segement size, 155f08c3bdfSopenharmony_ci * the number of attaches and the mode. 156f08c3bdfSopenharmony_ci */ 157f08c3bdfSopenharmony_cistatic void func_stat(void) 158f08c3bdfSopenharmony_ci{ 159f08c3bdfSopenharmony_ci pid_t pid; 160f08c3bdfSopenharmony_ci unsigned int num; 161f08c3bdfSopenharmony_ci 162f08c3bdfSopenharmony_ci /* check perm, pid, nattach and size */ 163f08c3bdfSopenharmony_ci pid = getpid(); 164f08c3bdfSopenharmony_ci 165f08c3bdfSopenharmony_ci if (buf.shm_cpid != pid) { 166f08c3bdfSopenharmony_ci tst_res(TFAIL, "creator pid is incorrect"); 167f08c3bdfSopenharmony_ci goto fail; 168f08c3bdfSopenharmony_ci } 169f08c3bdfSopenharmony_ci 170f08c3bdfSopenharmony_ci if (buf.shm_segsz != shm_size) { 171f08c3bdfSopenharmony_ci tst_res(TFAIL, "segment size is incorrect"); 172f08c3bdfSopenharmony_ci goto fail; 173f08c3bdfSopenharmony_ci } 174f08c3bdfSopenharmony_ci 175f08c3bdfSopenharmony_ci /* 176f08c3bdfSopenharmony_ci * The first case, only the children attach the memory, so 177f08c3bdfSopenharmony_ci * the attaches equal N_ATTACH. The second case, the parent 178f08c3bdfSopenharmony_ci * attaches the memory and the children inherit that memory 179f08c3bdfSopenharmony_ci * so the attaches equal N_ATTACH + 1. 180f08c3bdfSopenharmony_ci */ 181f08c3bdfSopenharmony_ci num = (attach_to_parent == NULL) ? 0 : 1; 182f08c3bdfSopenharmony_ci if (buf.shm_nattch != N_ATTACH + num) { 183f08c3bdfSopenharmony_ci tst_res(TFAIL, "# of attaches is incorrect - %lu", 184f08c3bdfSopenharmony_ci (unsigned long)buf.shm_nattch); 185f08c3bdfSopenharmony_ci goto fail; 186f08c3bdfSopenharmony_ci } 187f08c3bdfSopenharmony_ci 188f08c3bdfSopenharmony_ci /* use MODE_MASK to make sure we are comparing the last 9 bits */ 189f08c3bdfSopenharmony_ci if ((buf.shm_perm.mode & MODE_MASK) != ((SHM_RW) & MODE_MASK)) { 190f08c3bdfSopenharmony_ci tst_res(TFAIL, "segment mode is incorrect"); 191f08c3bdfSopenharmony_ci goto fail; 192f08c3bdfSopenharmony_ci } 193f08c3bdfSopenharmony_ci 194f08c3bdfSopenharmony_ci tst_res(TPASS, "pid, size, # of attaches and mode are correct " 195f08c3bdfSopenharmony_ci "- pass #%d", num); 196f08c3bdfSopenharmony_ci 197f08c3bdfSopenharmony_cifail: 198f08c3bdfSopenharmony_ci stat_cleanup(); 199f08c3bdfSopenharmony_ci 200f08c3bdfSopenharmony_ci /* save the change time for use in the next test */ 201f08c3bdfSopenharmony_ci save_time = buf.shm_ctime; 202f08c3bdfSopenharmony_ci} 203f08c3bdfSopenharmony_ci 204f08c3bdfSopenharmony_ci/* 205f08c3bdfSopenharmony_ci * stat_cleanup() - signal the children to clean up after themselves and 206f08c3bdfSopenharmony_ci * have the parent make dessert, er, um, make that remove 207f08c3bdfSopenharmony_ci * the shared memory that is no longer needed. 208f08c3bdfSopenharmony_ci */ 209f08c3bdfSopenharmony_cistatic void stat_cleanup(void) 210f08c3bdfSopenharmony_ci{ 211f08c3bdfSopenharmony_ci unsigned int i; 212f08c3bdfSopenharmony_ci int status; 213f08c3bdfSopenharmony_ci 214f08c3bdfSopenharmony_ci /* wake up the childern so they can detach the memory and exit */ 215f08c3bdfSopenharmony_ci TST_CHECKPOINT_WAKE2(1, N_ATTACH); 216f08c3bdfSopenharmony_ci 217f08c3bdfSopenharmony_ci for (i = 0; i < N_ATTACH; i++) 218f08c3bdfSopenharmony_ci SAFE_WAIT(&status); 219f08c3bdfSopenharmony_ci 220f08c3bdfSopenharmony_ci /* remove the parent's shared memory if we set*/ 221f08c3bdfSopenharmony_ci if (attach_to_parent) { 222f08c3bdfSopenharmony_ci if (shmdt(attach_to_parent) == -1) 223f08c3bdfSopenharmony_ci tst_res(TFAIL | TERRNO, 224f08c3bdfSopenharmony_ci "shmdt in this function failed"); 225f08c3bdfSopenharmony_ci attach_to_parent = NULL; 226f08c3bdfSopenharmony_ci } 227f08c3bdfSopenharmony_ci} 228f08c3bdfSopenharmony_ci 229f08c3bdfSopenharmony_ci/* 230f08c3bdfSopenharmony_ci * set_setup() - set up for the IPC_SET command with shmctl() 231f08c3bdfSopenharmony_ci */ 232f08c3bdfSopenharmony_cistatic void set_setup(void) 233f08c3bdfSopenharmony_ci{ 234f08c3bdfSopenharmony_ci /* set up a new mode for the shared memory segment */ 235f08c3bdfSopenharmony_ci buf.shm_perm.mode = SHM_RW | NEWMODE; 236f08c3bdfSopenharmony_ci 237f08c3bdfSopenharmony_ci /* sleep for one second to get a different shm_ctime value */ 238f08c3bdfSopenharmony_ci sleep(1); 239f08c3bdfSopenharmony_ci} 240f08c3bdfSopenharmony_ci 241f08c3bdfSopenharmony_ci/* 242f08c3bdfSopenharmony_ci * func_set() - check the functionality of the IPC_SET command with shmctl() 243f08c3bdfSopenharmony_ci */ 244f08c3bdfSopenharmony_cistatic void func_set(void) 245f08c3bdfSopenharmony_ci{ 246f08c3bdfSopenharmony_ci /* first stat the shared memory to get the new data */ 247f08c3bdfSopenharmony_ci if (shmctl(shm_id_1, IPC_STAT, &buf) == -1) { 248f08c3bdfSopenharmony_ci tst_res(TFAIL | TERRNO, "shmctl in this function failed"); 249f08c3bdfSopenharmony_ci return; 250f08c3bdfSopenharmony_ci } 251f08c3bdfSopenharmony_ci 252f08c3bdfSopenharmony_ci if ((buf.shm_perm.mode & MODE_MASK) != ((SHM_RW | NEWMODE) & MODE_MASK)) { 253f08c3bdfSopenharmony_ci tst_res(TFAIL, "new mode is incorrect"); 254f08c3bdfSopenharmony_ci return; 255f08c3bdfSopenharmony_ci } 256f08c3bdfSopenharmony_ci 257f08c3bdfSopenharmony_ci if (save_time >= buf.shm_ctime) { 258f08c3bdfSopenharmony_ci tst_res(TFAIL, "change time is incorrect"); 259f08c3bdfSopenharmony_ci return; 260f08c3bdfSopenharmony_ci } 261f08c3bdfSopenharmony_ci 262f08c3bdfSopenharmony_ci tst_res(TPASS, "new mode and change time are correct"); 263f08c3bdfSopenharmony_ci} 264f08c3bdfSopenharmony_ci 265f08c3bdfSopenharmony_ci/* 266f08c3bdfSopenharmony_ci * func_rmid() - check the functionality of the IPC_RMID command with shmctl() 267f08c3bdfSopenharmony_ci */ 268f08c3bdfSopenharmony_cistatic void func_rmid(void) 269f08c3bdfSopenharmony_ci{ 270f08c3bdfSopenharmony_ci /* Do another shmctl() - we should get EINVAL */ 271f08c3bdfSopenharmony_ci if (shmctl(shm_id_1, IPC_STAT, &buf) != -1) 272f08c3bdfSopenharmony_ci tst_brk(TBROK, "shmctl in this function " 273f08c3bdfSopenharmony_ci "succeeded unexpectedly"); 274f08c3bdfSopenharmony_ci if (errno != EINVAL) 275f08c3bdfSopenharmony_ci tst_res(TFAIL | TERRNO, "shmctl in this function failed " 276f08c3bdfSopenharmony_ci "unexpectedly - expect errno=EINVAL, got"); 277f08c3bdfSopenharmony_ci else 278f08c3bdfSopenharmony_ci tst_res(TPASS, "shmctl in this function failed as expected, " 279f08c3bdfSopenharmony_ci "shared memory appears to be removed"); 280f08c3bdfSopenharmony_ci shm_id_1 = -1; 281f08c3bdfSopenharmony_ci} 282f08c3bdfSopenharmony_ci 283f08c3bdfSopenharmony_cistatic void setup(void) 284f08c3bdfSopenharmony_ci{ 285f08c3bdfSopenharmony_ci long hpage_size; 286f08c3bdfSopenharmony_ci 287f08c3bdfSopenharmony_ci if (tst_hugepages == 0) 288f08c3bdfSopenharmony_ci tst_brk(TCONF, "No enough hugepages for testing."); 289f08c3bdfSopenharmony_ci 290f08c3bdfSopenharmony_ci hpage_size = SAFE_READ_MEMINFO("Hugepagesize:") * 1024; 291f08c3bdfSopenharmony_ci 292f08c3bdfSopenharmony_ci shm_size = hpage_size * tst_hugepages / 2; 293f08c3bdfSopenharmony_ci update_shm_size(&shm_size); 294f08c3bdfSopenharmony_ci shmkey = getipckey(); 295f08c3bdfSopenharmony_ci} 296f08c3bdfSopenharmony_ci 297f08c3bdfSopenharmony_cistatic void cleanup(void) 298f08c3bdfSopenharmony_ci{ 299f08c3bdfSopenharmony_ci rm_shm(shm_id_1); 300f08c3bdfSopenharmony_ci} 301f08c3bdfSopenharmony_ci 302f08c3bdfSopenharmony_cistatic struct tst_test test = { 303f08c3bdfSopenharmony_ci .tcnt = ARRAY_SIZE(tcases), 304f08c3bdfSopenharmony_ci .needs_root = 1, 305f08c3bdfSopenharmony_ci .forks_child = 1, 306f08c3bdfSopenharmony_ci .options = (struct tst_option[]) { 307f08c3bdfSopenharmony_ci {"s:", &nr_opt, "Set the number of the been allocated hugepages"}, 308f08c3bdfSopenharmony_ci {} 309f08c3bdfSopenharmony_ci }, 310f08c3bdfSopenharmony_ci .setup = setup, 311f08c3bdfSopenharmony_ci .cleanup = cleanup, 312f08c3bdfSopenharmony_ci .test = test_hugeshmctl, 313f08c3bdfSopenharmony_ci .needs_checkpoints = 1, 314f08c3bdfSopenharmony_ci .hugepages = {128, TST_REQUEST}, 315f08c3bdfSopenharmony_ci}; 316