Home | History | Annotate | Download | only in cpuset
      1 /*
      2  * Copyright (C) 2010-2017  Red Hat, Inc.
      3  *
      4  * This program is free software;  you can redistribute it and/or modify
      5  * it under the terms of the GNU General Public License as published by
      6  * the Free Software Foundation; either version 2 of the License, or
      7  * (at your option) any later version.
      8  *
      9  * This program is distributed in the hope that it will be useful,
     10  * but WITHOUT ANY WARRANTY;  without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
     12  * the GNU General Public License for more details.
     13  *
     14  * Out Of Memory when changing cpuset's mems on NUMA. There was a
     15  * problem reported upstream that the allocator may see an empty
     16  * nodemask when changing cpuset's mems.
     17  * http://lkml.org/lkml/2010/5/4/77
     18  * http://lkml.org/lkml/2010/5/4/79
     19  * http://lkml.org/lkml/2010/5/4/80
     20  * This test is based on the reproducers for the above issue.
     21  */
     22 
     23 #include "config.h"
     24 #include <stdio.h>
     25 #include <sys/wait.h>
     26 #if HAVE_NUMA_H
     27 #include <numa.h>
     28 #endif
     29 #if HAVE_NUMAIF_H
     30 #include <numaif.h>
     31 #endif
     32 
     33 #include "mem.h"
     34 #include "numa_helper.h"
     35 
     36 #ifdef HAVE_NUMA_V2
     37 
     38 volatile int end;
     39 static int *nodes;
     40 static int nnodes;
     41 static long ncpus;
     42 
     43 static void sighandler(int signo LTP_ATTRIBUTE_UNUSED);
     44 static int mem_hog(void);
     45 static int mem_hog_cpuset(int ntasks);
     46 static long count_cpu(void);
     47 
     48 static void test_cpuset(void)
     49 {
     50 	int child, i, status;
     51 	unsigned long nmask[MAXNODES / BITS_PER_LONG] = { 0 };
     52 	char mems[BUFSIZ], buf[BUFSIZ];
     53 
     54 	read_cpuset_files(CPATH, "cpus", buf);
     55 	write_cpuset_files(CPATH_NEW, "cpus", buf);
     56 	read_cpuset_files(CPATH, "mems", mems);
     57 	write_cpuset_files(CPATH_NEW, "mems", mems);
     58 	SAFE_FILE_PRINTF(CPATH_NEW "/tasks", "%d", getpid());
     59 
     60 	child = SAFE_FORK();
     61 	if (child == 0) {
     62 		for (i = 0; i < nnodes; i++) {
     63 			if (nodes[i] >= MAXNODES)
     64 				continue;
     65 			set_node(nmask, nodes[i]);
     66 		}
     67 		if (set_mempolicy(MPOL_BIND, nmask, MAXNODES) == -1)
     68 			tst_brk(TBROK | TERRNO, "set_mempolicy");
     69 		exit(mem_hog_cpuset(ncpus > 1 ? ncpus : 1));
     70 	}
     71 
     72 	snprintf(buf, BUFSIZ, "%d", nodes[0]);
     73 	write_cpuset_files(CPATH_NEW, "mems", buf);
     74 	snprintf(buf, BUFSIZ, "%d", nodes[1]);
     75 	write_cpuset_files(CPATH_NEW, "mems", buf);
     76 
     77 	SAFE_WAITPID(child, &status, WUNTRACED | WCONTINUED);
     78 	if (WEXITSTATUS(status) != 0) {
     79 		tst_res(TFAIL, "child exit status is %d", WEXITSTATUS(status));
     80 		return;
     81 	}
     82 
     83 	tst_res(TPASS, "cpuset test pass");
     84 }
     85 
     86 static void setup(void)
     87 {
     88 	mount_mem("cpuset", "cpuset", NULL, CPATH, CPATH_NEW);
     89 	ncpus = count_cpu();
     90 	if (get_allowed_nodes_arr(NH_MEMS | NH_CPUS, &nnodes, &nodes) < 0)
     91 		tst_brk(TBROK | TERRNO, "get_allowed_nodes_arr");
     92 	if (nnodes <= 1)
     93 		tst_brk(TCONF, "requires a NUMA system.");
     94 }
     95 
     96 static void cleanup(void)
     97 {
     98 	umount_mem(CPATH, CPATH_NEW);
     99 }
    100 
    101 static void sighandler(int signo LTP_ATTRIBUTE_UNUSED)
    102 {
    103 	end = 1;
    104 }
    105 
    106 static int mem_hog(void)
    107 {
    108 	long pagesize;
    109 	unsigned long *addr;
    110 	int ret = 0;
    111 
    112 	pagesize = getpagesize();
    113 	while (!end) {
    114 		addr = SAFE_MMAP(NULL, pagesize * 10, PROT_READ | PROT_WRITE,
    115 			    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    116 		memset(addr, 0xF7, pagesize * 10);
    117 		SAFE_MUNMAP(addr, pagesize * 10);
    118 	}
    119 	return ret;
    120 }
    121 
    122 static int mem_hog_cpuset(int ntasks)
    123 {
    124 	int i, status, ret = 0;
    125 	struct sigaction sa;
    126 	pid_t *pids;
    127 
    128 	if (ntasks <= 0)
    129 		tst_brk(TBROK | TERRNO, "ntasks is small.");
    130 	sa.sa_handler = sighandler;
    131 	if (sigemptyset(&sa.sa_mask) < 0)
    132 		tst_brk(TBROK | TERRNO, "sigemptyset");
    133 	sa.sa_flags = 0;
    134 	if (sigaction(SIGUSR1, &sa, NULL) < 0)
    135 		tst_brk(TBROK | TERRNO, "sigaction");
    136 
    137 	pids = SAFE_MALLOC(sizeof(pid_t) * ntasks);
    138 	for (i = 0; i < ntasks; i++) {
    139 		switch (pids[i] = fork()) {
    140 		case -1:
    141 			tst_res(TFAIL | TERRNO, "fork %d", pids[i]);
    142 			ret = 1;
    143 			break;
    144 		case 0:
    145 			ret = mem_hog();
    146 			exit(ret);
    147 		default:
    148 			break;
    149 		}
    150 	}
    151 
    152 	while (i--) {
    153 		if (kill(pids[i], SIGUSR1) == -1) {
    154 			tst_res(TFAIL | TERRNO, "kill %d", pids[i]);
    155 			ret = 1;
    156 		}
    157 	}
    158 	while (waitpid(-1, &status, WUNTRACED | WCONTINUED) > 0) {
    159 		if (WIFEXITED(status)) {
    160 			if (WEXITSTATUS(status) != 0) {
    161 				tst_res(TFAIL, "child exit status is %d",
    162 					 WEXITSTATUS(status));
    163 				ret = 1;
    164 			}
    165 		} else if (WIFSIGNALED(status)) {
    166 			tst_res(TFAIL, "child caught signal %d",
    167 				 WTERMSIG(status));
    168 			ret = 1;
    169 		}
    170 	}
    171 	return ret;
    172 }
    173 
    174 static long count_cpu(void)
    175 {
    176 	int ncpus = 0;
    177 
    178 	while (path_exist(PATH_SYS_SYSTEM "/cpu/cpu%d", ncpus))
    179 		ncpus++;
    180 
    181 	return ncpus;
    182 }
    183 
    184 static struct tst_test test = {
    185 	.needs_root = 1,
    186 	.setup = setup,
    187 	.cleanup = cleanup,
    188 	.test_all = test_cpuset,
    189 	.min_kver = "2.6.32",
    190 };
    191 
    192 #else
    193 	TST_TEST_TCONF("test requires libnuma >= 2 and it's development packages");
    194 #endif
    195