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  *	hugeshmctl02 - check for EACCES, EFAULT and EINVAL errors
19  *
20  * ALGORITHM
21  *	create a large shared memory segment without read or write permissions
22  *	create a large shared memory segment with read & write permissions
23  *	loop if that option was specified
24  *	  call shmctl() using five different invalid cases
25  *	  check the errno value
26  *	    issue a PASS message if we get EACCES, EFAULT or EINVAL
27  *	  otherwise, the tests fails
28  *	    issue a FAIL message
29  *	call cleanup
30  *
31  * HISTORY
32  *	03/2001 - Written by Wayne Boyer
33  *	04/2004 - Updated by Robbie Williamson
34  */
35 
36 #include <pwd.h>
37 #include <limits.h>
38 #include "hugetlb.h"
39 
40 static size_t shm_size;
41 static int shm_id_1 = -1;
42 static int shm_id_2 = -1;
43 static int shm_id_3 = -1;
44 static struct shmid_ds buf;
45 
46 static long hugepages = 128;
47 
48 static struct tst_option options[] = {
49 	{"s:", &nr_opt, "-s   num  Set the number of the been allocated hugepages"},
50 	{NULL, NULL, NULL}
51 };
52 
53 struct tcase {
54 	int *shmid;
55 	int cmd;
56 	struct shmid_ds *sbuf;
57 	int error;
58 } tcases[] = {
59 	/* EFAULT - IPC_SET & buf isn't valid */
60 	{&shm_id_2, IPC_SET, (struct shmid_ds *)-1, EFAULT},
61 	/* EFAULT - IPC_STAT & buf isn't valid */
62 	{&shm_id_2, IPC_STAT, (struct shmid_ds *)-1, EFAULT},
63 	/* EINVAL - the shmid is not valid */
64 	{&shm_id_3, IPC_STAT, &buf, EINVAL},
65 	/* EINVAL - the command is not valid */
66 	{&shm_id_2, -1, &buf, EINVAL},
67 };
68 
test_hugeshmctl(void)69 static void test_hugeshmctl(void)
70 {
71 	unsigned int i;
72 
73 	for (i = 0; i < ARRAY_SIZE(tcases); i++) {
74 		TEST(shmctl(*(tcases[i].shmid), tcases[i].cmd, tcases[i].sbuf));
75 		if (TST_RET != -1) {
76 			tst_res(TFAIL, "shmctl succeeded "
77 					"unexpectedly");
78 			continue;
79 		}
80 		if (TST_ERR == tcases[i].error) {
81 			tst_res(TPASS | TTERRNO, "shmctl failed "
82 					"as expected");
83 		} else {
84 			tst_res(TFAIL | TTERRNO, "shmctl failed "
85 					"unexpectedly - expect errno = "
86 					"%d, got", tcases[i].error);
87 		}
88 	}
89 }
90 
setup(void)91 static void setup(void)
92 {
93 	long hpage_size;
94 
95 	save_nr_hugepages();
96 	if (nr_opt)
97 		hugepages = SAFE_STRTOL(nr_opt, 0, LONG_MAX);
98 
99 	limit_hugepages(&hugepages);
100 	set_sys_tune("nr_hugepages", hugepages, 1);
101 	hpage_size = SAFE_READ_MEMINFO("Hugepagesize:") * 1024;
102 
103 	shm_size = hpage_size * (hugepages / 2);
104 	update_shm_size(&shm_size);
105 	shmkey = getipckey();
106 
107 	/* create a shared memory segment without read or write permissions */
108 	shm_id_1 = shmget(shmkey, shm_size, SHM_HUGETLB | IPC_CREAT | IPC_EXCL);
109 	if (shm_id_1 == -1)
110 		tst_brk(TBROK | TERRNO, "shmget #1");
111 
112 	/* create a shared memory segment with read and write permissions */
113 	shm_id_2 = shmget(shmkey + 1, shm_size,
114 			  SHM_HUGETLB | IPC_CREAT | IPC_EXCL | SHM_RW);
115 	if (shm_id_2 == -1)
116 		tst_brk(TBROK | TERRNO, "shmget #2");
117 }
118 
cleanup(void)119 static void cleanup(void)
120 {
121 	rm_shm(shm_id_1);
122 	rm_shm(shm_id_2);
123 	restore_nr_hugepages();
124 }
125 
126 static struct tst_test test = {
127 	.needs_root = 1,
128 	.needs_tmpdir = 1,
129 	.options = options,
130 	.setup = setup,
131 	.cleanup = cleanup,
132 	.test_all = test_hugeshmctl,
133 };
134