Home | History | Annotate | Download | only in hugeshmdt
      1 /*
      2  * Copyright (c) International Business Machines  Corp., 2004
      3  * Copyright (c) Linux Test Project, 2004-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  *	hugeshmdt01 - check that largr shared memory is detached correctly
     19  *
     20  * ALGORITHM
     21  *	create a large shared memory resource
     22  *	attach it to the current process and give it a value
     23  *	call shmdt() using the TEST macro
     24  *	check the return code
     25  *	  if failure, issue a FAIL message.
     26  *	otherwise,
     27  *	  if doing functionality testing
     28  *		attempt to write a value to the large shared memory address
     29  *		this should generate a SIGSEGV which will be caught in
     30  *		    the signal handler
     31  *		if correct,
     32  *			issue a PASS message
     33  *		otherwise
     34  *			issue a FAIL message
     35  *	call cleanup
     36  *
     37  * HISTORY
     38  *	03/2001 - Written by Wayne Boyer
     39  *	04/2004 - Updated by Robbie Williamson
     40  */
     41 
     42 #include <setjmp.h>
     43 #include <limits.h>
     44 #include "hugetlb.h"
     45 #include "hugetlb.h"
     46 
     47 static size_t shm_size;
     48 static int shm_id_1 = -1;
     49 struct shmid_ds buf;
     50 static int *shared;
     51 static int pass;
     52 static sigjmp_buf env;
     53 
     54 static long hugepages = 128;
     55 static struct tst_option options[] = {
     56 	{"s:", &nr_opt, "-s   num  Set the number of the been allocated hugepages"},
     57 	{NULL, NULL, NULL}
     58 };
     59 
     60 static void check_functionality(void);
     61 static void sighandler(int sig);
     62 
     63 static void hugeshmdt_test(void)
     64 {
     65 	struct sigaction sa;
     66 
     67 	sa.sa_handler = sighandler;
     68 	sigaction(SIGSEGV, &sa, NULL);
     69 
     70 	if (shmdt(shared) == -1)
     71 		tst_res(TFAIL | TERRNO, "shmdt");
     72 	else
     73 		check_functionality();
     74 
     75 	/* reattach the shared memory segment in case we are looping */
     76 	shared = shmat(shm_id_1, 0, 0);
     77 	if (shared == (void *)-1)
     78 		tst_brk(TBROK | TERRNO, "shmat #2: reattach");
     79 
     80 	/* also reset pass */
     81 	pass = 0;
     82 }
     83 
     84 static void check_functionality(void)
     85 {
     86 	/* stat the shared memory segment */
     87 	if (shmctl(shm_id_1, IPC_STAT, &buf) == -1)
     88 		tst_brk(TBROK | TERRNO, "shmctl");
     89 
     90 	if (buf.shm_nattch != 0) {
     91 		tst_res(TFAIL, "# of attaches is incorrect");
     92 		return;
     93 	}
     94 
     95 	/*
     96 	 * Try writing to the shared memory.  This should generate a
     97 	 * SIGSEGV which will be caught below.
     98 	 *
     99 	 * This is wrapped by the sigsetjmp() call that will take care of
    100 	 * restoring the program's context in an elegant way in conjunction
    101 	 * with the call to siglongjmp() in the signal handler.
    102 	 *
    103 	 * An attempt to do the assignment without using the sigsetjmp()
    104 	 * and siglongjmp() calls will result in an infinite loop.  Program
    105 	 * control is returned to the assignment statement after the execution
    106 	 * of the signal handler and another SIGSEGV will be generated.
    107 	 */
    108 
    109 	if (sigsetjmp(env, 1) == 0)
    110 		*shared = 2;
    111 
    112 	if (pass)
    113 		tst_res(TPASS, "huge shared memory detached correctly");
    114 	else
    115 		tst_res(TFAIL, "huge shared memory was not detached "
    116 			 "correctly");
    117 }
    118 
    119 static void sighandler(int sig)
    120 {
    121 	/* if we have received a SIGSEGV, we are almost done */
    122 	if (sig == SIGSEGV) {
    123 		/* set the global variable and jump back */
    124 		pass = 1;
    125 		siglongjmp(env, 1);
    126 	} else {
    127 		tst_brk(TBROK, "unexpected signal received: %d", sig);
    128 	}
    129 }
    130 
    131 void setup(void)
    132 {
    133 	long hpage_size;
    134 
    135 	save_nr_hugepages();
    136 	if (nr_opt)
    137 		hugepages = SAFE_STRTOL(nr_opt, 0, LONG_MAX);
    138 
    139 	set_sys_tune("nr_hugepages", hugepages, 1);
    140 	hpage_size = SAFE_READ_MEMINFO("Hugepagesize:") * 1024;
    141 
    142 	shm_size = hpage_size * hugepages / 2;
    143 	update_shm_size(&shm_size);
    144 	shmkey = getipckey();
    145 
    146 	/* create a shared memory resource with read and write permissions */
    147 	shm_id_1 = shmget(shmkey, shm_size,
    148 			  SHM_HUGETLB | SHM_RW | IPC_CREAT | IPC_EXCL);
    149 	if (shm_id_1 == -1)
    150 		tst_brk(TBROK | TERRNO, "shmget");
    151 
    152 	/* attach the shared memory segment */
    153 	shared = shmat(shm_id_1, 0, 0);
    154 	if (shared == (void *)-1)
    155 		tst_brk(TBROK | TERRNO, "shmat #1");
    156 
    157 	/* give a value to the shared memory integer */
    158 	*shared = 4;
    159 }
    160 
    161 void cleanup(void)
    162 {
    163 	rm_shm(shm_id_1);
    164 	restore_nr_hugepages();
    165 }
    166 
    167 static struct tst_test test = {
    168 	.needs_root = 1,
    169 	.options = options,
    170 	.setup = setup,
    171 	.cleanup = cleanup,
    172 	.test_all = hugeshmdt_test,
    173 };
    174