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 set_sys_tune("nr_hugepages", hugepages, 1);
100 hpage_size = SAFE_READ_MEMINFO("Hugepagesize:") * 1024;
101
102 shm_size = hpage_size * (hugepages / 2);
103 update_shm_size(&shm_size);
104 shmkey = getipckey();
105
106 /* create a shared memory segment without read or write permissions */
107 shm_id_1 = shmget(shmkey, shm_size, SHM_HUGETLB | IPC_CREAT | IPC_EXCL);
108 if (shm_id_1 == -1)
109 tst_brk(TBROK | TERRNO, "shmget #1");
110
111 /* create a shared memory segment with read and write permissions */
112 shm_id_2 = shmget(shmkey + 1, shm_size,
113 SHM_HUGETLB | IPC_CREAT | IPC_EXCL | SHM_RW);
114 if (shm_id_2 == -1)
115 tst_brk(TBROK | TERRNO, "shmget #2");
116 }
117
cleanup(void)118 static void cleanup(void)
119 {
120 rm_shm(shm_id_1);
121 rm_shm(shm_id_2);
122 restore_nr_hugepages();
123 }
124
125 static struct tst_test test = {
126 .needs_root = 1,
127 .needs_tmpdir = 1,
128 .options = options,
129 .setup = setup,
130 .cleanup = cleanup,
131 .test_all = test_hugeshmctl,
132 };
133