1*49cdfc7eSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0-or-later
2*49cdfc7eSAndroid Build Coastguard Worker /*
3*49cdfc7eSAndroid Build Coastguard Worker * Copyright (c) 2023 Oracle and/or its affiliates.
4*49cdfc7eSAndroid Build Coastguard Worker */
5*49cdfc7eSAndroid Build Coastguard Worker
6*49cdfc7eSAndroid Build Coastguard Worker /*\
7*49cdfc7eSAndroid Build Coastguard Worker * [Description]
8*49cdfc7eSAndroid Build Coastguard Worker *
9*49cdfc7eSAndroid Build Coastguard Worker * Stress a possible race condition between memory pages allocation
10*49cdfc7eSAndroid Build Coastguard Worker * and soft-offline of unrelated pages as explained in the commit:
11*49cdfc7eSAndroid Build Coastguard Worker * d4ae9916ea29 (mm: soft-offline: close the race against page allocation)
12*49cdfc7eSAndroid Build Coastguard Worker *
13*49cdfc7eSAndroid Build Coastguard Worker * Control that soft-offlined pages get correctly replaced: with the
14*49cdfc7eSAndroid Build Coastguard Worker * same content and without SIGBUS generation when accessed.
15*49cdfc7eSAndroid Build Coastguard Worker */
16*49cdfc7eSAndroid Build Coastguard Worker
17*49cdfc7eSAndroid Build Coastguard Worker #include <errno.h>
18*49cdfc7eSAndroid Build Coastguard Worker #include <mntent.h>
19*49cdfc7eSAndroid Build Coastguard Worker #include <pthread.h>
20*49cdfc7eSAndroid Build Coastguard Worker #include <stdio.h>
21*49cdfc7eSAndroid Build Coastguard Worker #include <stdlib.h>
22*49cdfc7eSAndroid Build Coastguard Worker #include <time.h>
23*49cdfc7eSAndroid Build Coastguard Worker #include <unistd.h>
24*49cdfc7eSAndroid Build Coastguard Worker #include <sys/types.h>
25*49cdfc7eSAndroid Build Coastguard Worker #include <sys/klog.h>
26*49cdfc7eSAndroid Build Coastguard Worker
27*49cdfc7eSAndroid Build Coastguard Worker #include "tst_test.h"
28*49cdfc7eSAndroid Build Coastguard Worker #include "tst_safe_pthread.h"
29*49cdfc7eSAndroid Build Coastguard Worker #include "tst_safe_stdio.h"
30*49cdfc7eSAndroid Build Coastguard Worker #include "lapi/mmap.h"
31*49cdfc7eSAndroid Build Coastguard Worker
32*49cdfc7eSAndroid Build Coastguard Worker #define NUM_LOOPS 5
33*49cdfc7eSAndroid Build Coastguard Worker #define NUM_PAGES 32
34*49cdfc7eSAndroid Build Coastguard Worker #define NUM_PAGES_OFFSET 5
35*49cdfc7eSAndroid Build Coastguard Worker
36*49cdfc7eSAndroid Build Coastguard Worker /* Needed module to online back memory pages */
37*49cdfc7eSAndroid Build Coastguard Worker #define HW_MODULE "hwpoison_inject"
38*49cdfc7eSAndroid Build Coastguard Worker
39*49cdfc7eSAndroid Build Coastguard Worker static pthread_t *thread_ids;
40*49cdfc7eSAndroid Build Coastguard Worker static int number_threads;
41*49cdfc7eSAndroid Build Coastguard Worker static int run_iterations;
42*49cdfc7eSAndroid Build Coastguard Worker static int maximum_pfns;
43*49cdfc7eSAndroid Build Coastguard Worker
44*49cdfc7eSAndroid Build Coastguard Worker static volatile int sigbus_received;
45*49cdfc7eSAndroid Build Coastguard Worker static pthread_cond_t sigbus_received_cv;
46*49cdfc7eSAndroid Build Coastguard Worker static pthread_mutex_t sigbus_received_mtx = PTHREAD_MUTEX_INITIALIZER;
47*49cdfc7eSAndroid Build Coastguard Worker
48*49cdfc7eSAndroid Build Coastguard Worker static long pagesize;
49*49cdfc7eSAndroid Build Coastguard Worker static char beginning_tag[BUFSIZ];
50*49cdfc7eSAndroid Build Coastguard Worker static int hwpoison_probe;
51*49cdfc7eSAndroid Build Coastguard Worker
my_yield(void)52*49cdfc7eSAndroid Build Coastguard Worker static void my_yield(void)
53*49cdfc7eSAndroid Build Coastguard Worker {
54*49cdfc7eSAndroid Build Coastguard Worker static const struct timespec t0 = { 0, 0 };
55*49cdfc7eSAndroid Build Coastguard Worker
56*49cdfc7eSAndroid Build Coastguard Worker nanosleep(&t0, NULL);
57*49cdfc7eSAndroid Build Coastguard Worker }
58*49cdfc7eSAndroid Build Coastguard Worker
59*49cdfc7eSAndroid Build Coastguard Worker /* a SIGBUS received is a confirmation of test failure */
sigbus_handler(int signum LTP_ATTRIBUTE_UNUSED)60*49cdfc7eSAndroid Build Coastguard Worker static void sigbus_handler(int signum LTP_ATTRIBUTE_UNUSED)
61*49cdfc7eSAndroid Build Coastguard Worker {
62*49cdfc7eSAndroid Build Coastguard Worker pthread_mutex_lock(&sigbus_received_mtx);
63*49cdfc7eSAndroid Build Coastguard Worker sigbus_received++;
64*49cdfc7eSAndroid Build Coastguard Worker pthread_cond_signal(&sigbus_received_cv);
65*49cdfc7eSAndroid Build Coastguard Worker pthread_mutex_unlock(&sigbus_received_mtx);
66*49cdfc7eSAndroid Build Coastguard Worker pause();
67*49cdfc7eSAndroid Build Coastguard Worker }
68*49cdfc7eSAndroid Build Coastguard Worker
sigbus_monitor(void * arg LTP_ATTRIBUTE_UNUSED)69*49cdfc7eSAndroid Build Coastguard Worker static void *sigbus_monitor(void *arg LTP_ATTRIBUTE_UNUSED)
70*49cdfc7eSAndroid Build Coastguard Worker {
71*49cdfc7eSAndroid Build Coastguard Worker pthread_mutex_lock(&sigbus_received_mtx);
72*49cdfc7eSAndroid Build Coastguard Worker while (!sigbus_received)
73*49cdfc7eSAndroid Build Coastguard Worker pthread_cond_wait(&sigbus_received_cv, &sigbus_received_mtx);
74*49cdfc7eSAndroid Build Coastguard Worker pthread_mutex_unlock(&sigbus_received_mtx);
75*49cdfc7eSAndroid Build Coastguard Worker tst_res(TFAIL, "SIGBUS Received");
76*49cdfc7eSAndroid Build Coastguard Worker exit(1);
77*49cdfc7eSAndroid Build Coastguard Worker }
78*49cdfc7eSAndroid Build Coastguard Worker
79*49cdfc7eSAndroid Build Coastguard Worker /*
80*49cdfc7eSAndroid Build Coastguard Worker * Allocate a page and write a sentinel value into it.
81*49cdfc7eSAndroid Build Coastguard Worker */
allocate_write(int sentinel)82*49cdfc7eSAndroid Build Coastguard Worker static void *allocate_write(int sentinel)
83*49cdfc7eSAndroid Build Coastguard Worker {
84*49cdfc7eSAndroid Build Coastguard Worker void *p;
85*49cdfc7eSAndroid Build Coastguard Worker int *s;
86*49cdfc7eSAndroid Build Coastguard Worker
87*49cdfc7eSAndroid Build Coastguard Worker p = SAFE_MMAP(NULL, pagesize, PROT_READ|PROT_WRITE,
88*49cdfc7eSAndroid Build Coastguard Worker MAP_SHARED|MAP_ANONYMOUS, -1, 0);
89*49cdfc7eSAndroid Build Coastguard Worker s = (int *)p;
90*49cdfc7eSAndroid Build Coastguard Worker *s = sentinel;
91*49cdfc7eSAndroid Build Coastguard Worker return p;
92*49cdfc7eSAndroid Build Coastguard Worker }
93*49cdfc7eSAndroid Build Coastguard Worker
94*49cdfc7eSAndroid Build Coastguard Worker /*
95*49cdfc7eSAndroid Build Coastguard Worker * Verify and unmap the given page.
96*49cdfc7eSAndroid Build Coastguard Worker */
verif_unmap(void * page,int sentinel)97*49cdfc7eSAndroid Build Coastguard Worker static int verif_unmap(void *page, int sentinel)
98*49cdfc7eSAndroid Build Coastguard Worker {
99*49cdfc7eSAndroid Build Coastguard Worker int *s = (int *)page;
100*49cdfc7eSAndroid Build Coastguard Worker
101*49cdfc7eSAndroid Build Coastguard Worker if (*s != sentinel) {
102*49cdfc7eSAndroid Build Coastguard Worker tst_res(TFAIL, "pid[%d]: fail: bad sentinel value seen: %d expected: %d\n", getpid(), *s, sentinel);
103*49cdfc7eSAndroid Build Coastguard Worker return 1;
104*49cdfc7eSAndroid Build Coastguard Worker }
105*49cdfc7eSAndroid Build Coastguard Worker
106*49cdfc7eSAndroid Build Coastguard Worker return SAFE_MUNMAP(page, pagesize);
107*49cdfc7eSAndroid Build Coastguard Worker }
108*49cdfc7eSAndroid Build Coastguard Worker
109*49cdfc7eSAndroid Build Coastguard Worker /*
110*49cdfc7eSAndroid Build Coastguard Worker * allocate_offline() - Allocate and offline test called per-thread
111*49cdfc7eSAndroid Build Coastguard Worker *
112*49cdfc7eSAndroid Build Coastguard Worker * This function does the allocation and offline by mmapping an
113*49cdfc7eSAndroid Build Coastguard Worker * anonymous page and offlining it.
114*49cdfc7eSAndroid Build Coastguard Worker */
allocate_offline(int tnum)115*49cdfc7eSAndroid Build Coastguard Worker static int allocate_offline(int tnum)
116*49cdfc7eSAndroid Build Coastguard Worker {
117*49cdfc7eSAndroid Build Coastguard Worker int loop;
118*49cdfc7eSAndroid Build Coastguard Worker
119*49cdfc7eSAndroid Build Coastguard Worker for (loop = 0; loop < NUM_LOOPS; loop++) {
120*49cdfc7eSAndroid Build Coastguard Worker long *ptrs[NUM_PAGES];
121*49cdfc7eSAndroid Build Coastguard Worker int num_alloc;
122*49cdfc7eSAndroid Build Coastguard Worker int i;
123*49cdfc7eSAndroid Build Coastguard Worker
124*49cdfc7eSAndroid Build Coastguard Worker for (num_alloc = 0; num_alloc < NUM_PAGES; num_alloc++) {
125*49cdfc7eSAndroid Build Coastguard Worker
126*49cdfc7eSAndroid Build Coastguard Worker ptrs[num_alloc] = allocate_write((tnum << NUM_PAGES_OFFSET) | num_alloc);
127*49cdfc7eSAndroid Build Coastguard Worker if (ptrs[num_alloc] == NULL)
128*49cdfc7eSAndroid Build Coastguard Worker return -1;
129*49cdfc7eSAndroid Build Coastguard Worker
130*49cdfc7eSAndroid Build Coastguard Worker if (madvise(ptrs[num_alloc], pagesize, MADV_SOFT_OFFLINE) == -1) {
131*49cdfc7eSAndroid Build Coastguard Worker if (errno == EBUSY)
132*49cdfc7eSAndroid Build Coastguard Worker continue;
133*49cdfc7eSAndroid Build Coastguard Worker if (errno != EINVAL)
134*49cdfc7eSAndroid Build Coastguard Worker tst_res(TFAIL | TERRNO, "madvise failed");
135*49cdfc7eSAndroid Build Coastguard Worker if (errno == EINVAL)
136*49cdfc7eSAndroid Build Coastguard Worker tst_res(TCONF, "madvise() didn't support MADV_SOFT_OFFLINE");
137*49cdfc7eSAndroid Build Coastguard Worker return errno;
138*49cdfc7eSAndroid Build Coastguard Worker }
139*49cdfc7eSAndroid Build Coastguard Worker }
140*49cdfc7eSAndroid Build Coastguard Worker
141*49cdfc7eSAndroid Build Coastguard Worker for (i = 0; i < num_alloc; i++) {
142*49cdfc7eSAndroid Build Coastguard Worker if (verif_unmap(ptrs[i], (tnum << NUM_PAGES_OFFSET) | i) != 0)
143*49cdfc7eSAndroid Build Coastguard Worker return 1;
144*49cdfc7eSAndroid Build Coastguard Worker }
145*49cdfc7eSAndroid Build Coastguard Worker
146*49cdfc7eSAndroid Build Coastguard Worker my_yield();
147*49cdfc7eSAndroid Build Coastguard Worker if (!tst_remaining_runtime()) {
148*49cdfc7eSAndroid Build Coastguard Worker tst_res(TINFO, "Thread [%d]: Test runtime is over, exiting", tnum);
149*49cdfc7eSAndroid Build Coastguard Worker break;
150*49cdfc7eSAndroid Build Coastguard Worker }
151*49cdfc7eSAndroid Build Coastguard Worker }
152*49cdfc7eSAndroid Build Coastguard Worker
153*49cdfc7eSAndroid Build Coastguard Worker return 0;
154*49cdfc7eSAndroid Build Coastguard Worker }
155*49cdfc7eSAndroid Build Coastguard Worker
alloc_mem(void * threadnum)156*49cdfc7eSAndroid Build Coastguard Worker static void *alloc_mem(void *threadnum)
157*49cdfc7eSAndroid Build Coastguard Worker {
158*49cdfc7eSAndroid Build Coastguard Worker int err;
159*49cdfc7eSAndroid Build Coastguard Worker int tnum = (int)(uintptr_t)threadnum;
160*49cdfc7eSAndroid Build Coastguard Worker
161*49cdfc7eSAndroid Build Coastguard Worker /* waiting for other threads starting */
162*49cdfc7eSAndroid Build Coastguard Worker TST_CHECKPOINT_WAIT(0);
163*49cdfc7eSAndroid Build Coastguard Worker
164*49cdfc7eSAndroid Build Coastguard Worker err = allocate_offline(tnum);
165*49cdfc7eSAndroid Build Coastguard Worker tst_res(TINFO,
166*49cdfc7eSAndroid Build Coastguard Worker "Thread [%d] returned %d, %s.", tnum, err, (err ? "failed" : "succeeded"));
167*49cdfc7eSAndroid Build Coastguard Worker return (void *)(uintptr_t) (err ? -1 : 0);
168*49cdfc7eSAndroid Build Coastguard Worker }
169*49cdfc7eSAndroid Build Coastguard Worker
stress_alloc_offl(void)170*49cdfc7eSAndroid Build Coastguard Worker static void stress_alloc_offl(void)
171*49cdfc7eSAndroid Build Coastguard Worker {
172*49cdfc7eSAndroid Build Coastguard Worker int thread_index;
173*49cdfc7eSAndroid Build Coastguard Worker int thread_failure = 0;
174*49cdfc7eSAndroid Build Coastguard Worker pthread_t sigbus_monitor_t;
175*49cdfc7eSAndroid Build Coastguard Worker
176*49cdfc7eSAndroid Build Coastguard Worker run_iterations++;
177*49cdfc7eSAndroid Build Coastguard Worker
178*49cdfc7eSAndroid Build Coastguard Worker SAFE_PTHREAD_CREATE(&sigbus_monitor_t, NULL, sigbus_monitor, NULL);
179*49cdfc7eSAndroid Build Coastguard Worker pthread_detach(sigbus_monitor_t);
180*49cdfc7eSAndroid Build Coastguard Worker
181*49cdfc7eSAndroid Build Coastguard Worker for (thread_index = 0; thread_index < number_threads; thread_index++) {
182*49cdfc7eSAndroid Build Coastguard Worker SAFE_PTHREAD_CREATE(&thread_ids[thread_index], NULL, alloc_mem,
183*49cdfc7eSAndroid Build Coastguard Worker (void *)(uintptr_t)thread_index);
184*49cdfc7eSAndroid Build Coastguard Worker }
185*49cdfc7eSAndroid Build Coastguard Worker
186*49cdfc7eSAndroid Build Coastguard Worker TST_CHECKPOINT_WAKE2(0, number_threads);
187*49cdfc7eSAndroid Build Coastguard Worker
188*49cdfc7eSAndroid Build Coastguard Worker for (thread_index = 0; thread_index < number_threads; thread_index++) {
189*49cdfc7eSAndroid Build Coastguard Worker void *status;
190*49cdfc7eSAndroid Build Coastguard Worker
191*49cdfc7eSAndroid Build Coastguard Worker SAFE_PTHREAD_JOIN(thread_ids[thread_index], &status);
192*49cdfc7eSAndroid Build Coastguard Worker if ((intptr_t)status != 0) {
193*49cdfc7eSAndroid Build Coastguard Worker tst_res(TFAIL, "thread [%d] - exited with errors",
194*49cdfc7eSAndroid Build Coastguard Worker thread_index);
195*49cdfc7eSAndroid Build Coastguard Worker thread_failure++;
196*49cdfc7eSAndroid Build Coastguard Worker }
197*49cdfc7eSAndroid Build Coastguard Worker }
198*49cdfc7eSAndroid Build Coastguard Worker
199*49cdfc7eSAndroid Build Coastguard Worker if (thread_failure == 0)
200*49cdfc7eSAndroid Build Coastguard Worker tst_res(TPASS, "soft-offline / mmap race still clean");
201*49cdfc7eSAndroid Build Coastguard Worker }
202*49cdfc7eSAndroid Build Coastguard Worker
203*49cdfc7eSAndroid Build Coastguard Worker /*
204*49cdfc7eSAndroid Build Coastguard Worker * ------------
205*49cdfc7eSAndroid Build Coastguard Worker * Cleanup code:
206*49cdfc7eSAndroid Build Coastguard Worker * The idea is to retrieve all the pfn numbers that have been soft-offined
207*49cdfc7eSAndroid Build Coastguard Worker * (generating a "Soft offlining pfn 0x..." message in the kernel ring buffer)
208*49cdfc7eSAndroid Build Coastguard Worker * by the current test (since a "beginning_tag" message we write when starting).
209*49cdfc7eSAndroid Build Coastguard Worker * And to put these pages back online by writing the pfn number to the
210*49cdfc7eSAndroid Build Coastguard Worker * <debugfs>/hwpoison/unpoison-pfn special file.
211*49cdfc7eSAndroid Build Coastguard Worker * ------------
212*49cdfc7eSAndroid Build Coastguard Worker */
213*49cdfc7eSAndroid Build Coastguard Worker #define OFFLINE_PATTERN "Soft offlining pfn 0x"
214*49cdfc7eSAndroid Build Coastguard Worker #define OFFLINE_PATTERN_LEN sizeof(OFFLINE_PATTERN)
215*49cdfc7eSAndroid Build Coastguard Worker
216*49cdfc7eSAndroid Build Coastguard Worker /* return the pfn if the kmsg msg is a soft-offline indication*/
parse_kmsg_soft_offlined_pfn(char * line,ssize_t len)217*49cdfc7eSAndroid Build Coastguard Worker static unsigned long parse_kmsg_soft_offlined_pfn(char *line, ssize_t len)
218*49cdfc7eSAndroid Build Coastguard Worker {
219*49cdfc7eSAndroid Build Coastguard Worker char *pos;
220*49cdfc7eSAndroid Build Coastguard Worker unsigned long addr = 0UL;
221*49cdfc7eSAndroid Build Coastguard Worker
222*49cdfc7eSAndroid Build Coastguard Worker pos = strstr(line, OFFLINE_PATTERN);
223*49cdfc7eSAndroid Build Coastguard Worker if (pos == NULL)
224*49cdfc7eSAndroid Build Coastguard Worker return 0UL;
225*49cdfc7eSAndroid Build Coastguard Worker
226*49cdfc7eSAndroid Build Coastguard Worker pos += OFFLINE_PATTERN_LEN-1;
227*49cdfc7eSAndroid Build Coastguard Worker if (pos > (line + len))
228*49cdfc7eSAndroid Build Coastguard Worker return 0UL;
229*49cdfc7eSAndroid Build Coastguard Worker
230*49cdfc7eSAndroid Build Coastguard Worker addr = strtoul(pos, NULL, 16);
231*49cdfc7eSAndroid Build Coastguard Worker if ((addr == ULONG_MAX) && (errno == ERANGE))
232*49cdfc7eSAndroid Build Coastguard Worker return 0UL;
233*49cdfc7eSAndroid Build Coastguard Worker
234*49cdfc7eSAndroid Build Coastguard Worker return addr;
235*49cdfc7eSAndroid Build Coastguard Worker }
236*49cdfc7eSAndroid Build Coastguard Worker
237*49cdfc7eSAndroid Build Coastguard Worker /* return the pfns seen in kernel message log */
populate_from_klog(char * begin_tag,unsigned long * pfns,int max)238*49cdfc7eSAndroid Build Coastguard Worker static int populate_from_klog(char *begin_tag, unsigned long *pfns, int max)
239*49cdfc7eSAndroid Build Coastguard Worker {
240*49cdfc7eSAndroid Build Coastguard Worker int found = 0, fd, beginning_tag_found = 0;
241*49cdfc7eSAndroid Build Coastguard Worker ssize_t sz;
242*49cdfc7eSAndroid Build Coastguard Worker unsigned long pfn;
243*49cdfc7eSAndroid Build Coastguard Worker char buf[BUFSIZ];
244*49cdfc7eSAndroid Build Coastguard Worker
245*49cdfc7eSAndroid Build Coastguard Worker fd = SAFE_OPEN("/dev/kmsg", O_RDONLY|O_NONBLOCK);
246*49cdfc7eSAndroid Build Coastguard Worker
247*49cdfc7eSAndroid Build Coastguard Worker while (found < max) {
248*49cdfc7eSAndroid Build Coastguard Worker sz = read(fd, buf, sizeof(buf));
249*49cdfc7eSAndroid Build Coastguard Worker /* kmsg returns EPIPE if record was modified while reading */
250*49cdfc7eSAndroid Build Coastguard Worker if (sz < 0 && errno == EPIPE)
251*49cdfc7eSAndroid Build Coastguard Worker continue;
252*49cdfc7eSAndroid Build Coastguard Worker if (sz <= 0)
253*49cdfc7eSAndroid Build Coastguard Worker break;
254*49cdfc7eSAndroid Build Coastguard Worker if (!beginning_tag_found) {
255*49cdfc7eSAndroid Build Coastguard Worker if (strstr(buf, begin_tag))
256*49cdfc7eSAndroid Build Coastguard Worker beginning_tag_found = 1;
257*49cdfc7eSAndroid Build Coastguard Worker continue;
258*49cdfc7eSAndroid Build Coastguard Worker }
259*49cdfc7eSAndroid Build Coastguard Worker pfn = parse_kmsg_soft_offlined_pfn(buf, sz);
260*49cdfc7eSAndroid Build Coastguard Worker if (pfn)
261*49cdfc7eSAndroid Build Coastguard Worker pfns[found++] = pfn;
262*49cdfc7eSAndroid Build Coastguard Worker }
263*49cdfc7eSAndroid Build Coastguard Worker SAFE_CLOSE(fd);
264*49cdfc7eSAndroid Build Coastguard Worker return found;
265*49cdfc7eSAndroid Build Coastguard Worker }
266*49cdfc7eSAndroid Build Coastguard Worker
267*49cdfc7eSAndroid Build Coastguard Worker /*
268*49cdfc7eSAndroid Build Coastguard Worker * Read the given file to search for the key.
269*49cdfc7eSAndroid Build Coastguard Worker * Return 1 if the key is found.
270*49cdfc7eSAndroid Build Coastguard Worker */
find_in_file(char * path,char * key)271*49cdfc7eSAndroid Build Coastguard Worker static int find_in_file(char *path, char *key)
272*49cdfc7eSAndroid Build Coastguard Worker {
273*49cdfc7eSAndroid Build Coastguard Worker char line[4096];
274*49cdfc7eSAndroid Build Coastguard Worker int found = 0;
275*49cdfc7eSAndroid Build Coastguard Worker FILE *file = SAFE_FOPEN(path, "r");
276*49cdfc7eSAndroid Build Coastguard Worker
277*49cdfc7eSAndroid Build Coastguard Worker while (fgets(line, sizeof(line), file)) {
278*49cdfc7eSAndroid Build Coastguard Worker if (strstr(line, key)) {
279*49cdfc7eSAndroid Build Coastguard Worker found = 1;
280*49cdfc7eSAndroid Build Coastguard Worker break;
281*49cdfc7eSAndroid Build Coastguard Worker }
282*49cdfc7eSAndroid Build Coastguard Worker }
283*49cdfc7eSAndroid Build Coastguard Worker SAFE_FCLOSE(file);
284*49cdfc7eSAndroid Build Coastguard Worker return found;
285*49cdfc7eSAndroid Build Coastguard Worker }
286*49cdfc7eSAndroid Build Coastguard Worker
unpoison_this_pfn(unsigned long pfn,int fd)287*49cdfc7eSAndroid Build Coastguard Worker static void unpoison_this_pfn(unsigned long pfn, int fd)
288*49cdfc7eSAndroid Build Coastguard Worker {
289*49cdfc7eSAndroid Build Coastguard Worker char pfn_str[19];
290*49cdfc7eSAndroid Build Coastguard Worker
291*49cdfc7eSAndroid Build Coastguard Worker snprintf(pfn_str, sizeof(pfn_str), "0x%lx", pfn);
292*49cdfc7eSAndroid Build Coastguard Worker SAFE_WRITE(0, fd, pfn_str, strlen(pfn_str));
293*49cdfc7eSAndroid Build Coastguard Worker }
294*49cdfc7eSAndroid Build Coastguard Worker
295*49cdfc7eSAndroid Build Coastguard Worker /* Find and open the <debugfs>/hwpoison/unpoison-pfn special file */
open_unpoison_pfn(void)296*49cdfc7eSAndroid Build Coastguard Worker static int open_unpoison_pfn(void)
297*49cdfc7eSAndroid Build Coastguard Worker {
298*49cdfc7eSAndroid Build Coastguard Worker char *added_file_path = "/hwpoison/unpoison-pfn";
299*49cdfc7eSAndroid Build Coastguard Worker const char *const cmd_modprobe[] = {"modprobe", HW_MODULE, NULL};
300*49cdfc7eSAndroid Build Coastguard Worker char debugfs_fp[4096];
301*49cdfc7eSAndroid Build Coastguard Worker struct mntent *mnt;
302*49cdfc7eSAndroid Build Coastguard Worker FILE *mntf;
303*49cdfc7eSAndroid Build Coastguard Worker
304*49cdfc7eSAndroid Build Coastguard Worker if (!find_in_file("/proc/modules", HW_MODULE) && tst_check_builtin_driver(HW_MODULE))
305*49cdfc7eSAndroid Build Coastguard Worker hwpoison_probe = 1;
306*49cdfc7eSAndroid Build Coastguard Worker
307*49cdfc7eSAndroid Build Coastguard Worker /* probe hwpoison only if it isn't already there */
308*49cdfc7eSAndroid Build Coastguard Worker if (hwpoison_probe)
309*49cdfc7eSAndroid Build Coastguard Worker SAFE_CMD(cmd_modprobe, NULL, NULL);
310*49cdfc7eSAndroid Build Coastguard Worker
311*49cdfc7eSAndroid Build Coastguard Worker /* debugfs mount point */
312*49cdfc7eSAndroid Build Coastguard Worker mntf = setmntent("/proc/mounts", "r");
313*49cdfc7eSAndroid Build Coastguard Worker if (!mntf) {
314*49cdfc7eSAndroid Build Coastguard Worker tst_brk(TBROK | TERRNO, "Can't open /proc/mounts");
315*49cdfc7eSAndroid Build Coastguard Worker return -1;
316*49cdfc7eSAndroid Build Coastguard Worker }
317*49cdfc7eSAndroid Build Coastguard Worker while ((mnt = getmntent(mntf)) != NULL) {
318*49cdfc7eSAndroid Build Coastguard Worker if (strcmp(mnt->mnt_type, "debugfs") == 0) {
319*49cdfc7eSAndroid Build Coastguard Worker strcpy(debugfs_fp, mnt->mnt_dir);
320*49cdfc7eSAndroid Build Coastguard Worker strcat(debugfs_fp, added_file_path);
321*49cdfc7eSAndroid Build Coastguard Worker break;
322*49cdfc7eSAndroid Build Coastguard Worker }
323*49cdfc7eSAndroid Build Coastguard Worker }
324*49cdfc7eSAndroid Build Coastguard Worker endmntent(mntf);
325*49cdfc7eSAndroid Build Coastguard Worker if (!mnt)
326*49cdfc7eSAndroid Build Coastguard Worker return -1;
327*49cdfc7eSAndroid Build Coastguard Worker
328*49cdfc7eSAndroid Build Coastguard Worker TEST(open(debugfs_fp, O_WRONLY));
329*49cdfc7eSAndroid Build Coastguard Worker
330*49cdfc7eSAndroid Build Coastguard Worker if (TST_RET == -1 && TST_ERR == EPERM && tst_lockdown_enabled() > 0) {
331*49cdfc7eSAndroid Build Coastguard Worker tst_res(TINFO,
332*49cdfc7eSAndroid Build Coastguard Worker "Cannot restore soft-offlined memory due to lockdown");
333*49cdfc7eSAndroid Build Coastguard Worker return TST_RET;
334*49cdfc7eSAndroid Build Coastguard Worker }
335*49cdfc7eSAndroid Build Coastguard Worker
336*49cdfc7eSAndroid Build Coastguard Worker if (TST_RET == -1) {
337*49cdfc7eSAndroid Build Coastguard Worker tst_brk(TBROK | TTERRNO, "open(%s) failed", debugfs_fp);
338*49cdfc7eSAndroid Build Coastguard Worker } else if (TST_RET < 0) {
339*49cdfc7eSAndroid Build Coastguard Worker tst_brk(TBROK | TTERRNO, "Invalid open() return value %ld",
340*49cdfc7eSAndroid Build Coastguard Worker TST_RET);
341*49cdfc7eSAndroid Build Coastguard Worker }
342*49cdfc7eSAndroid Build Coastguard Worker
343*49cdfc7eSAndroid Build Coastguard Worker return TST_RET;
344*49cdfc7eSAndroid Build Coastguard Worker }
345*49cdfc7eSAndroid Build Coastguard Worker
346*49cdfc7eSAndroid Build Coastguard Worker /*
347*49cdfc7eSAndroid Build Coastguard Worker * Get all the Offlined PFNs indicated in the dmesg output
348*49cdfc7eSAndroid Build Coastguard Worker * starting after the given beginning tag, and request a debugfs
349*49cdfc7eSAndroid Build Coastguard Worker * hwpoison/unpoison-pfn for each of them.
350*49cdfc7eSAndroid Build Coastguard Worker */
unpoison_pfn(char * begin_tag)351*49cdfc7eSAndroid Build Coastguard Worker static void unpoison_pfn(char *begin_tag)
352*49cdfc7eSAndroid Build Coastguard Worker {
353*49cdfc7eSAndroid Build Coastguard Worker unsigned long *pfns;
354*49cdfc7eSAndroid Build Coastguard Worker const char *const cmd_rmmod[] = {"rmmod", HW_MODULE, NULL};
355*49cdfc7eSAndroid Build Coastguard Worker int found_pfns, fd;
356*49cdfc7eSAndroid Build Coastguard Worker
357*49cdfc7eSAndroid Build Coastguard Worker pfns = SAFE_MALLOC(sizeof(pfns) * maximum_pfns * run_iterations);
358*49cdfc7eSAndroid Build Coastguard Worker
359*49cdfc7eSAndroid Build Coastguard Worker fd = open_unpoison_pfn();
360*49cdfc7eSAndroid Build Coastguard Worker if (fd >= 0) {
361*49cdfc7eSAndroid Build Coastguard Worker found_pfns = populate_from_klog(begin_tag, pfns, maximum_pfns * run_iterations);
362*49cdfc7eSAndroid Build Coastguard Worker
363*49cdfc7eSAndroid Build Coastguard Worker tst_res(TINFO, "Restore %d Soft-offlined pages", found_pfns);
364*49cdfc7eSAndroid Build Coastguard Worker /* unpoison in reverse order */
365*49cdfc7eSAndroid Build Coastguard Worker while (found_pfns-- > 0)
366*49cdfc7eSAndroid Build Coastguard Worker unpoison_this_pfn(pfns[found_pfns], fd);
367*49cdfc7eSAndroid Build Coastguard Worker
368*49cdfc7eSAndroid Build Coastguard Worker SAFE_CLOSE(fd);
369*49cdfc7eSAndroid Build Coastguard Worker }
370*49cdfc7eSAndroid Build Coastguard Worker /* remove hwpoison only if we probed it */
371*49cdfc7eSAndroid Build Coastguard Worker if (hwpoison_probe)
372*49cdfc7eSAndroid Build Coastguard Worker SAFE_CMD(cmd_rmmod, NULL, NULL);
373*49cdfc7eSAndroid Build Coastguard Worker }
374*49cdfc7eSAndroid Build Coastguard Worker
375*49cdfc7eSAndroid Build Coastguard Worker /*
376*49cdfc7eSAndroid Build Coastguard Worker * Create and write a beginning tag to the kernel buffer to be used on cleanup
377*49cdfc7eSAndroid Build Coastguard Worker * when trying to restore the soft-offlined pages of our test run.
378*49cdfc7eSAndroid Build Coastguard Worker */
write_beginning_tag_to_kmsg(void)379*49cdfc7eSAndroid Build Coastguard Worker static void write_beginning_tag_to_kmsg(void)
380*49cdfc7eSAndroid Build Coastguard Worker {
381*49cdfc7eSAndroid Build Coastguard Worker int fd;
382*49cdfc7eSAndroid Build Coastguard Worker
383*49cdfc7eSAndroid Build Coastguard Worker fd = SAFE_OPEN("/dev/kmsg", O_WRONLY);
384*49cdfc7eSAndroid Build Coastguard Worker snprintf(beginning_tag, sizeof(beginning_tag),
385*49cdfc7eSAndroid Build Coastguard Worker "Soft-offlining pages test starting (pid: %ld)",
386*49cdfc7eSAndroid Build Coastguard Worker (long)getpid());
387*49cdfc7eSAndroid Build Coastguard Worker SAFE_WRITE(1, fd, beginning_tag, strlen(beginning_tag));
388*49cdfc7eSAndroid Build Coastguard Worker SAFE_CLOSE(fd);
389*49cdfc7eSAndroid Build Coastguard Worker }
390*49cdfc7eSAndroid Build Coastguard Worker
setup(void)391*49cdfc7eSAndroid Build Coastguard Worker static void setup(void)
392*49cdfc7eSAndroid Build Coastguard Worker {
393*49cdfc7eSAndroid Build Coastguard Worker struct sigaction my_sigaction;
394*49cdfc7eSAndroid Build Coastguard Worker
395*49cdfc7eSAndroid Build Coastguard Worker number_threads = (int)sysconf(_SC_NPROCESSORS_ONLN) * 2;
396*49cdfc7eSAndroid Build Coastguard Worker if (number_threads <= 1)
397*49cdfc7eSAndroid Build Coastguard Worker number_threads = 2;
398*49cdfc7eSAndroid Build Coastguard Worker else if (number_threads > 5)
399*49cdfc7eSAndroid Build Coastguard Worker number_threads = 5;
400*49cdfc7eSAndroid Build Coastguard Worker
401*49cdfc7eSAndroid Build Coastguard Worker maximum_pfns = number_threads * NUM_LOOPS * NUM_PAGES;
402*49cdfc7eSAndroid Build Coastguard Worker thread_ids = SAFE_MALLOC(sizeof(pthread_t) * number_threads);
403*49cdfc7eSAndroid Build Coastguard Worker pagesize = sysconf(_SC_PAGESIZE);
404*49cdfc7eSAndroid Build Coastguard Worker
405*49cdfc7eSAndroid Build Coastguard Worker /* SIGBUS is the main failure criteria */
406*49cdfc7eSAndroid Build Coastguard Worker my_sigaction.sa_handler = sigbus_handler;
407*49cdfc7eSAndroid Build Coastguard Worker if (sigaction(SIGBUS, &my_sigaction, NULL) == -1)
408*49cdfc7eSAndroid Build Coastguard Worker tst_res(TFAIL | TERRNO, "Signal handler attach failed");
409*49cdfc7eSAndroid Build Coastguard Worker
410*49cdfc7eSAndroid Build Coastguard Worker write_beginning_tag_to_kmsg();
411*49cdfc7eSAndroid Build Coastguard Worker tst_res(TINFO, "Spawning %d threads, with a total of %d memory pages",
412*49cdfc7eSAndroid Build Coastguard Worker number_threads, maximum_pfns);
413*49cdfc7eSAndroid Build Coastguard Worker }
414*49cdfc7eSAndroid Build Coastguard Worker
cleanup(void)415*49cdfc7eSAndroid Build Coastguard Worker static void cleanup(void)
416*49cdfc7eSAndroid Build Coastguard Worker {
417*49cdfc7eSAndroid Build Coastguard Worker unpoison_pfn(beginning_tag);
418*49cdfc7eSAndroid Build Coastguard Worker }
419*49cdfc7eSAndroid Build Coastguard Worker
420*49cdfc7eSAndroid Build Coastguard Worker static struct tst_test test = {
421*49cdfc7eSAndroid Build Coastguard Worker .needs_root = 1,
422*49cdfc7eSAndroid Build Coastguard Worker .needs_drivers = (const char *const []) {
423*49cdfc7eSAndroid Build Coastguard Worker HW_MODULE,
424*49cdfc7eSAndroid Build Coastguard Worker NULL
425*49cdfc7eSAndroid Build Coastguard Worker },
426*49cdfc7eSAndroid Build Coastguard Worker .needs_cmds = (const char *[]) {
427*49cdfc7eSAndroid Build Coastguard Worker "modprobe",
428*49cdfc7eSAndroid Build Coastguard Worker "rmmod",
429*49cdfc7eSAndroid Build Coastguard Worker NULL
430*49cdfc7eSAndroid Build Coastguard Worker },
431*49cdfc7eSAndroid Build Coastguard Worker .needs_kconfigs = (const char *[]) {
432*49cdfc7eSAndroid Build Coastguard Worker "CONFIG_MEMORY_FAILURE=y",
433*49cdfc7eSAndroid Build Coastguard Worker NULL
434*49cdfc7eSAndroid Build Coastguard Worker },
435*49cdfc7eSAndroid Build Coastguard Worker .max_runtime = 30,
436*49cdfc7eSAndroid Build Coastguard Worker .needs_checkpoints = 1,
437*49cdfc7eSAndroid Build Coastguard Worker .setup = setup,
438*49cdfc7eSAndroid Build Coastguard Worker .cleanup = cleanup,
439*49cdfc7eSAndroid Build Coastguard Worker .test_all = stress_alloc_offl,
440*49cdfc7eSAndroid Build Coastguard Worker .tags = (const struct tst_tag[]) {
441*49cdfc7eSAndroid Build Coastguard Worker {"linux-git", "d4ae9916ea29"},
442*49cdfc7eSAndroid Build Coastguard Worker {}
443*49cdfc7eSAndroid Build Coastguard Worker }
444*49cdfc7eSAndroid Build Coastguard Worker };
445