Home | History | Annotate | Download | only in hugeshmat
      1 /*
      2  * Copyright (c) International Business Machines  Corp., 2001
      3  * Copyright (c) Linux Test Project, 2001-2017
      4  *
      5  * This program is free software;  you can redistribute it and/or modify
      6  * it under the terms of the GNU General Public License as published by
      7  * the Free Software Foundation; either version 2 of the License, or
      8  * (at your option) any later version.
      9  *
     10  * This program is distributed in the hope that it will be useful,
     11  * but WITHOUT ANY WARRANTY;  without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
     13  * the GNU General Public License for more details.
     14  */
     15 
     16 /*
     17  * DESCRIPTION
     18  *	hugeshmat01 - test that shmat() works correctly
     19  *
     20  * ALGORITHM
     21  *	create a large shared memory resouce with read/write permissions
     22  *	loop if that option was specified
     23  *	call shmat() with the TEST() macro using three valid conditions
     24  *	check the return code
     25  *	  if failure, issue a FAIL message.
     26  *	otherwise,
     27  *	  if doing functionality testing
     28  *		check for the correct conditions after the call
     29  *		if correct,
     30  *			issue a PASS message
     31  *		otherwise
     32  *			issue a FAIL message
     33  *	call cleanup
     34  *
     35  * HISTORY
     36  *	03/2001 - Written by Wayne Boyer
     37  *	04/2004 - Updated by Robbie Williamson
     38  */
     39 
     40 #include <limits.h>
     41 #include "hugetlb.h"
     42 
     43 #define CASE0 10 /* values to write into the shared */
     44 #define CASE1 20 /* memory location.                */
     45 
     46 static size_t shm_size;
     47 static int shm_id_1 = -1;
     48 static void *addr;
     49 
     50 static long hugepages = 128;
     51 
     52 static struct tst_option options[] = {
     53 	{"s:", &nr_opt, "-s   num  Set the number of the been allocated hugepages"},
     54 	{NULL, NULL, NULL}
     55 };
     56 
     57 static struct tcase {
     58 	int *shmid;
     59 	void *addr;
     60 	int flags;
     61 } tcases[] = {
     62 	/* a straight forward read/write attach */
     63 	{&shm_id_1, 0, 0},
     64 	/*
     65 	 * an attach using non aligned memory
     66 	 * -1 will be replaced with an unaligned addr
     67 	 */
     68 	{&shm_id_1, (void *)-1, SHM_RND},
     69 	/* a read only attach */
     70 	{&shm_id_1, 0, SHM_RDONLY}
     71 };
     72 
     73 static void check_functionality(unsigned int i);
     74 
     75 static void verify_hugeshmat(unsigned int i)
     76 {
     77 	struct tcase *tc = &tcases[i];
     78 
     79 	addr = shmat(*(tc->shmid), tc->addr, tc->flags);
     80 	if (addr == (void *)-1) {
     81 		tst_brk(TFAIL | TERRNO, "shmat");
     82 	} else {
     83 		check_functionality(i);
     84 	}
     85 
     86 	/*
     87 	 * addr in tcases[0] will be used to generate an unaligned
     88 	 * address for tcases[1]
     89 	 */
     90 	if (i == 0 && addr != (void *)-1)
     91 		tc[1].addr = (void *)(((unsigned long)addr &
     92 					~(SHMLBA - 1)) + SHMLBA - 1);
     93 	if (shmdt(addr) == -1)
     94 		tst_brk(TBROK | TERRNO, "shmdt");
     95 }
     96 
     97 /*
     98  * check_functionality - check various conditions to make sure they
     99  *			 are correct.
    100  */
    101 static void check_functionality(unsigned int i)
    102 {
    103 	void *orig_add;
    104 	int *shared;
    105 	struct shmid_ds buf;
    106 
    107 	shared = (int *)addr;
    108 
    109 	/* stat the shared memory ID */
    110 	if (shmctl(shm_id_1, IPC_STAT, &buf) == -1)
    111 		tst_brk(TBROK | TERRNO, "shmctl");
    112 
    113 	/* check the number of attaches */
    114 	if (buf.shm_nattch != 1) {
    115 		tst_res(TFAIL, "# of attaches is incorrect");
    116 		return;
    117 	}
    118 
    119 	/* check the size of the segment */
    120 	if (buf.shm_segsz != shm_size) {
    121 		tst_res(TFAIL, "segment size is incorrect");
    122 		return;
    123 	}
    124 
    125 	/* check for specific conditions depending on the type of attach */
    126 	switch (i) {
    127 	case 0:
    128 		/*
    129 		 * Check the functionality of the first call by simply
    130 		 * "writing" a value to the shared memory space.
    131 		 * If this fails the program will get a SIGSEGV, dump
    132 		 * core and exit.
    133 		 */
    134 		*shared = CASE0;
    135 		break;
    136 	case 1:
    137 		/*
    138 		 * Check the functionality of the second call by writing
    139 		 * a value to the shared memory space and then checking
    140 		 * that the original address given was rounded down as
    141 		 * specified in the man page.
    142 		 */
    143 		*shared = CASE1;
    144 		orig_add = addr + ((unsigned long)tcases[i].addr % SHMLBA);
    145 		if (orig_add != tcases[i].addr) {
    146 			tst_res(TFAIL, "shared memory address is not "
    147 				 "correct");
    148 			return;
    149 		}
    150 		break;
    151 	case 2:
    152 		/*
    153 		 * This time the shared memory is read only.  Read the value
    154 		 * and check that it is equal to the value set in case #2,
    155 		 * because shared memory is persistent.
    156 		 */
    157 		if (*shared != CASE1) {
    158 			tst_res(TFAIL, "shared memory value isn't correct");
    159 			return;
    160 		}
    161 		break;
    162 	}
    163 	tst_res(TPASS, "conditions and functionality are correct");
    164 }
    165 
    166 static void setup(void)
    167 {
    168 	long hpage_size;
    169 
    170 	save_nr_hugepages();
    171 	if (nr_opt)
    172 		hugepages = SAFE_STRTOL(nr_opt, 0, LONG_MAX);
    173 
    174 	set_sys_tune("nr_hugepages", hugepages, 1);
    175 	hpage_size = SAFE_READ_MEMINFO("Hugepagesize:") * 1024;
    176 
    177 	shm_size = hpage_size * hugepages / 2;
    178 	update_shm_size(&shm_size);
    179 	shmkey = getipckey();
    180 	shm_id_1 = shmget(shmkey++, shm_size,
    181 			  SHM_HUGETLB | SHM_RW | IPC_CREAT | IPC_EXCL);
    182 	if (shm_id_1 == -1)
    183 		tst_brk(TBROK | TERRNO, "shmget");
    184 
    185 }
    186 
    187 static void cleanup(void)
    188 {
    189 	rm_shm(shm_id_1);
    190 	restore_nr_hugepages();
    191 }
    192 
    193 static struct tst_test test = {
    194 	.needs_root = 1,
    195 	.needs_tmpdir = 1,
    196 	.options = options,
    197 	.tcnt = ARRAY_SIZE(tcases),
    198 	.test = verify_hugeshmat,
    199 	.setup = setup,
    200 	.cleanup = cleanup,
    201 };
    202