2 * Copyright IBM Corp 2007
3 * Author: Hans-Joachim Picht <hans@linux.vnet.ibm.com>
5 * Linux for System z Hotplug Daemon
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include <sys/types.h>
34 pthread_mutex_t m
= PTHREAD_MUTEX_INITIALIZER
;
36 struct sigaction action_signal
;
38 /* save the initial values for the cleanup procedure */
40 int cmm_pagesize_start
;
47 * this functions handles the sigfpe signal which we
48 * might catch during rule evaluating
52 signal(SIGFPE
, handler
);
56 void eval_cpu_rules(struct config
*cfg
)
58 struct symbols symbols
;
60 int onumcpus
, runable_proc
;
63 onumcpus
= get_num_online_cpus();
64 runable_proc
= get_runable_proc();
65 idle_ticks
= get_idle_ticks();
66 symbols
.loadavg
= (double) get_loadavg();
67 symbols
.onumcpus
= (double) onumcpus
;
68 symbols
.runable_proc
= (double) runable_proc
;
69 symbols
.idle
= (double) (idle_ticks
- cfg
->idle_ticks
) / cfg
->update
;
70 cfg
->idle_ticks
= idle_ticks
;
71 nr_cpus
= get_numcpus();
73 /* only use this for development and testing */
74 if (debug
&& foreground
== 1) {
75 printf("---------------------------------------------\n");
76 printf("update_interval: %d s\n", cfg
->update
);
77 printf("cpu_min: %d\n", cfg
->cpu_min
);
78 printf("cpu_max: %d\n", cfg
->cpu_max
);
79 printf("loadavg: %f \n", symbols
.loadavg
);
80 printf("idle percent = %f\n", symbols
.idle
);
81 printf("numcpus %d\n", nr_cpus
);
82 printf("runable_proc: %d\n", runable_proc
);
83 printf("---------------------------------------------\n");
84 printf("onumcpus: %d\n", onumcpus
);
85 printf("---------------------------------------------\n");
88 print_term(cfg
->hotplug
);
92 printf("hotunplug: ");
93 print_term(cfg
->hotunplug
);
96 printf("---------------------------------------------\n");
98 /* Evaluate the hotplug rule. */
99 if (cfg
->hotplug
&& eval_term(cfg
->hotplug
, &symbols
)) {
100 /* check the cpu nr limit */
101 if (onumcpus
+ 1 > cfg
->cpu_max
) {
102 /* cpu limit reached */
105 printf("maximum cpu limit is "
108 syslog(LOG_INFO
, "maximum cpu"
109 " limit is reached\n");
113 /* try to find a offline cpu */
114 for (cpu
= 0; cpu
< nr_cpus
; cpu
++)
115 if (is_online(cpu
) == 0 && cpu_is_configured(cpu
) != 0)
118 if (debug
&& foreground
== 1)
119 printf("cpu with id %d is currently "
120 "offline and will be enabled\n",
122 if (debug
&& foreground
== 0)
123 syslog(LOG_INFO
, "CPU with id %d is "
124 "currently offline and will be "
126 if (hotplug(cpu
) == -1) {
127 if (debug
&& foreground
== 1)
128 printf("unable to find a cpu which "
130 if (debug
&& foreground
== 0)
131 syslog(LOG_INFO
, "unable to find a cpu"
132 " which can be enabled\n");
136 * in case we tried to enable a cpu but this failed.
137 * this is the case if a cpu is deconfigured
139 if (debug
&& foreground
== 1)
140 printf("unable to find a cpu which can be"
142 if (debug
&& foreground
== 0)
143 syslog(LOG_INFO
, "unable to find a cpu which"
148 /* Evaluate the hotplug rule. */
149 if (cfg
->hotunplug
&& eval_term(cfg
->hotunplug
, &symbols
)) {
150 /* check cpu nr limit */
151 if (onumcpus
<= cfg
->cpu_min
) {
154 printf("minimum cpu limit "
157 syslog(LOG_INFO
, "minimum cpu"
158 " limit is reached\n");
162 /* try to find a online cpu */
163 for (cpu
= get_numcpus() - 1; cpu
>= 0; cpu
--) {
164 if (is_online(cpu
) != 0)
168 if (debug
&& foreground
== 1)
169 printf("cpu with id %d is currently "
170 "online and will be disabled\n",
172 if (debug
&& foreground
== 0)
173 syslog(LOG_INFO
, "CPU with id %d is "
174 "currently online and will be "
182 void eval_mem_rules(struct config
*cfg
)
184 struct symbols symbols
;
186 int free_memory
= get_free_memsize();
188 if (free_memory
== -1) {
190 printf("Failed to retrieve the free mem size: "
193 syslog(LOG_INFO
, "Failed to retrieve the free mem size:"
197 cmmpages_size
= get_cmmpages_size();
199 symbols
.swaprate
= swaprate
;
200 symbols
.freemem
= free_memory
;
202 /* only use this for development and testing */
203 if (debug
&& foreground
== 1) {
204 printf("---------------------------------------------\n");
205 printf("update_interval: %d s\n", cfg
->update
);
206 printf("cmm_min: %d\n", cfg
->cmm_min
);
207 printf("cmm_max: %d\n", cfg
->cmm_max
);
208 printf("swaprate: %d\n", swaprate
);
209 printf("apcr: %d\n", apcr
);
210 printf("cmm_inc: %d\n", cfg
->cmm_inc
);
211 printf("free memory: %d MB\n", free_memory
);
212 printf("---------------------------------------------\n");
213 printf("cmm_pages: %d\n", cmmpages_size
);
214 printf("---------------------------------------------\n");
217 print_term(cfg
->memplug
);
220 if (cfg
->memunplug
) {
221 printf("memunplug: ");
222 print_term(cfg
->memunplug
);
225 printf("---------------------------------------------\n");
227 /* Evaluate the memunplug rule. */
228 if (cfg
->memunplug
&& eval_term(cfg
->memunplug
, &symbols
)) {
230 * case where cmm has asynchronously increased
231 * cmm_pages after cpuplugd reset it to cmm_max
232 * at cpuplugd startup.
235 if (cmmpages_size
> cfg
->cmm_max
) {
238 printf("Found cmm_pages above Limit. "
239 "Resetting value to %d\n"
242 syslog(LOG_INFO
, "Found cmm_pages above"
243 "Limit. Resetting value to %d\n"
246 set_cmm_pages(cfg
->cmm_max
);
249 /* check memory limit */
250 if (cmmpages_size
+ cfg
->cmm_inc
> cfg
->cmm_max
) {
253 printf("maximum memory limit "
256 syslog(LOG_INFO
, "maximum memory"
257 " limit is reached\n");
259 if (cmmpages_size
< cfg
->cmm_max
) {
260 /* if the next increment would exceed
261 * the maximum we advance to the
264 set_cmm_pages(cfg
->cmm_max
);
268 memunplug(cfg
->cmm_inc
);
272 /* Evaluate the memplug rule. */
273 if (cfg
->memplug
&& eval_term(cfg
->memplug
, &symbols
)) {
274 /* check memory limit */
275 if (cmmpages_size
- cfg
->cmm_inc
< cfg
->cmm_min
) {
278 printf("minimum memory limit "
281 syslog(LOG_INFO
, "minimum memory"
282 " limit is reached\n");
283 if (cmmpages_size
> cfg
->cmm_min
) {
284 /* if the next increment would exceed
285 * the minimum we advance to the
288 set_cmm_pages(cfg
->cmm_min
);
293 memplug(cfg
->cmm_inc
);
299 int main(int argc
, char *argv
[])
302 /* This is needed to validate the config file */
311 cfg
.memunplug
= NULL
;
313 cfg
.hotunplug
= NULL
;
314 /* parse the command line options */
315 parse_options(argc
, argv
);
316 /* make sure that the daemon is not started multiple times */
317 check_if_started_twice();
318 /* Store daemon pid also in foreground mode */
321 /* arguments taken from the configuration file */
322 parse_configfile(&cfg
, configfile
);
323 /*check if the required settings are found in the configuration file*/
330 fprintf(stderr
, "Detach from terminal failed: "
331 "%s\n", strerror(errno
));
333 syslog(LOG_INFO
, "Detach from terminal failed: "
334 "%s\n", strerror(errno
));
338 /* Store daemon pid */
340 /* thread to collect vmstat data */
341 pthread_t thread_id1
;
342 struct vmstat
*vs
= malloc(sizeof(struct vmstat
));
345 printf("Out of memory: Aborting.\n");
347 syslog(LOG_INFO
, "Out of memory: Aborting.\n");
351 * If the thread routine requires multiple arguments, they must be
352 * passed bundled up in an array or a structure
354 struct thread1_params t1args
;
357 if (pthread_create(&thread_id1
, NULL
, &get_info
, &t1args
)) {
359 printf("Failed to start thread.\n");
361 syslog(LOG_INFO
, "Failed to start thread\n");
363 /* ensure that reliable data from vmstat is gathered */
364 while (memory
== 1 && vs
->available
== 0)
368 cfg
.idle_ticks
= get_idle_ticks();
374 if (setjmp(buf
) == 0) {
376 /* install signal handler for floating point
380 sigaddset(&set
, SIGFPE
);
381 action_signal
.sa_flags
= 0;
382 sigemptyset(&action_signal
.sa_mask
);
383 action_signal
.sa_handler
= handler
;
384 sigaction(SIGFPE
, &action_signal
, NULL
);
385 /* Run code that may signal failure via longjmp. */
387 eval_cpu_rules(&cfg
);
389 eval_mem_rules(&cfg
);
393 sigprocmask(SIG_UNBLOCK
, &set
, NULL
);