4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
29 #include <sys/types.h>
34 #include <rcm_module.h>
42 static int pool_register(rcm_handle_t
*);
43 static int pool_unregister(rcm_handle_t
*);
44 static int pool_get_info(rcm_handle_t
*, char *, id_t
, uint_t
, char **,
45 char **, nvlist_t
*, rcm_info_t
**);
46 static int pool_request_suspend(rcm_handle_t
*, char *, id_t
,
47 timespec_t
*, uint_t
, char **, rcm_info_t
**);
48 static int pool_notify_resume(rcm_handle_t
*, char *, id_t
, uint_t
, char **,
50 static int pool_notify_remove(rcm_handle_t
*, char *, id_t
, uint_t
,
51 char **, rcm_info_t
**);
52 static int pool_request_offline(rcm_handle_t
*, char *, id_t
, uint_t
,
53 char **, rcm_info_t
**);
54 static int pool_notify_online(rcm_handle_t
*, char *, id_t
, uint_t
, char **,
56 static int pool_request_capacity_change(rcm_handle_t
*, char *, id_t
, uint_t
,
57 nvlist_t
*, char **, rcm_info_t
**);
58 static int pool_notify_capacity_change(rcm_handle_t
*, char *, id_t
, uint_t
,
59 nvlist_t
*, char **, rcm_info_t
**);
62 * Pool-specific callback functions.
64 static int pset_validate_remove(nvlist_t
*, char **);
68 int (*capacity_change_cb
)(nvlist_t
*, char **);
70 { "SUNW_cpu", pset_validate_remove
},
74 static int registered
= 0;
76 static struct rcm_mod_ops pool_ops
= {
86 pool_request_capacity_change
,
87 pool_notify_capacity_change
,
94 rcm_log_message(RCM_TRACE1
, "Pools RCM module created\n");
102 rcm_log_message(RCM_TRACE1
, "Pools RCM module unloaded\n");
103 return (RCM_SUCCESS
);
109 return ("Pools RCM module 1.4");
113 pool_check_pset(pool_conf_t
*conf
, pool_resource_t
*res
,
114 processorid_t
*del_cpus
, char **errorp
)
120 uint_t num_found
= 0;
121 processorid_t
*cpulist
;
124 pool_elem_t
*elem
= pool_resource_to_elem(conf
, res
);
126 if ((pval
= pool_value_alloc()) == NULL
)
128 if (pool_get_property(conf
, elem
, "pset.min", pval
) != POC_UINT
) {
129 rcm_log_message(RCM_ERROR
,
130 gettext("POOL: cannot find property 'pset.min' in pset\n"));
131 pool_value_free(pval
);
134 (void) pool_value_get_uint64(pval
, &min_cpus
);
135 if (pool_get_property(conf
, elem
, "pset.sys_id", pval
) != POC_INT
) {
136 rcm_log_message(RCM_ERROR
,
137 gettext("POOL: cannot get pset.sys_id\n"));
138 pool_value_free(pval
);
141 (void) pool_value_get_int64(pval
, &tmp
);
142 pool_value_free(pval
);
143 psetid
= (psetid_t
)tmp
;
144 rcm_log_message(RCM_TRACE1
, "POOL: checking pset: %d\n", psetid
);
146 rcm_log_message(RCM_TRACE1
, "POOL: min_cpus is %llu\n", min_cpus
);
147 if (pset_info(psetid
, NULL
, &num_cpus
, NULL
) != 0) {
148 rcm_log_message(RCM_ERROR
,
149 gettext("POOL: pset_info(%d) failed: %s\n"), psetid
,
153 if ((cpulist
= malloc(num_cpus
* sizeof (processorid_t
))) == NULL
) {
154 rcm_log_message(RCM_ERROR
,
155 gettext("POOL: malloc failed: %s\n"), strerror(errno
));
158 if (pset_info(psetid
, NULL
, &num_cpus
, cpulist
) != 0) {
160 rcm_log_message(RCM_ERROR
,
161 gettext("POOL: pset_info(%d) failed: %s\n"), psetid
,
165 for (i
= 0; del_cpus
[i
] != -1; i
++)
166 for (j
= 0; j
< num_cpus
; j
++)
167 if (cpulist
[j
] == del_cpus
[i
])
170 if (num_found
> 0 && (num_cpus
- num_found
) < (uint_t
)min_cpus
) {
174 gettext("POOL: processor set (%1$d) would go "
175 "below its minimum value of %2$u\n");
178 * We would go below the min value. Fail this request.
180 len
= strlen(errfmt
) + 4 * 2; /* 4 digits for psetid and min */
181 if ((errval
= malloc((len
+ 1) * sizeof (char))) != NULL
) {
182 (void) snprintf(errval
, len
+ 1, errfmt
, psetid
,
187 rcm_log_message(RCM_ERROR
, (char *)errfmt
, psetid
,
192 rcm_log_message(RCM_TRACE1
, "POOL: pset %d is fine\n", psetid
);
197 * pset_validate_remove()
198 * Check to see if the requested cpu removal would be acceptable.
199 * Returns RCM_FAILURE if not.
202 pset_validate_remove(nvlist_t
*nvl
, char **errorp
)
204 int error
= RCM_SUCCESS
;
205 int32_t old_total
, new_total
, removed_total
;
206 processorid_t
*removed_list
= NULL
; /* list terminated by (-1). */
207 processorid_t
*old_cpu_list
= NULL
, *new_cpu_list
= NULL
;
210 pool_value_t
*pvals
[] = { NULL
, NULL
};
211 pool_resource_t
**res
= NULL
;
213 const char *generic_error
= gettext("POOL: Error processing request\n");
215 if ((conf
= pool_conf_alloc()) == NULL
)
216 return (RCM_FAILURE
);
217 if (pool_conf_open(conf
, pool_dynamic_location(), PO_RDONLY
) < 0) {
218 rcm_log_message(RCM_TRACE1
,
219 "POOL: failed to parse config file: '%s'\n",
220 pool_dynamic_location());
221 pool_conf_free(conf
);
222 return (RCM_SUCCESS
);
225 if ((error
= nvlist_lookup_int32(nvl
, "old_total", &old_total
)) != 0) {
226 (void) pool_conf_close(conf
);
227 pool_conf_free(conf
);
228 rcm_log_message(RCM_ERROR
,
229 gettext("POOL: unable to find 'old_total' in nvlist: %s\n"),
231 *errorp
= strdup(generic_error
);
232 return (RCM_FAILURE
);
234 if ((error
= nvlist_lookup_int32(nvl
, "new_total", &new_total
)) != 0) {
235 (void) pool_conf_close(conf
);
236 pool_conf_free(conf
);
237 rcm_log_message(RCM_ERROR
,
238 gettext("POOL: unable to find 'new_total' in nvlist: %s\n"),
240 *errorp
= strdup(generic_error
);
241 return (RCM_FAILURE
);
243 if (new_total
>= old_total
) {
244 (void) pool_conf_close(conf
);
245 pool_conf_free(conf
);
247 * This doesn't look like a cpu removal.
249 rcm_log_message(RCM_TRACE1
,
250 gettext("POOL: 'old_total' (%d) is less than 'new_total' "
251 "(%d)\n"), old_total
, new_total
);
252 return (RCM_SUCCESS
);
254 if ((removed_list
= malloc((old_total
- new_total
+ 1) * sizeof (int)))
256 rcm_log_message(RCM_ERROR
,
257 gettext("POOL: malloc failed: %s\n"), strerror(errno
));
262 if ((error
= nvlist_lookup_int32_array(nvl
, "old_cpu_list",
263 &old_cpu_list
, &nelem
)) != 0) {
264 rcm_log_message(RCM_ERROR
,
265 gettext("POOL: 'old_cpu_list' not found in nvlist: %s\n"),
270 if ((int32_t)nelem
!= old_total
) {
271 rcm_log_message(RCM_ERROR
,
272 gettext("POOL: 'old_cpu_list' size mismatch: %1$d vs "
273 "%2$d\n"), nelem
, old_total
);
277 if ((error
= nvlist_lookup_int32_array(nvl
, "new_cpu_list",
278 &new_cpu_list
, &nelem
)) != 0) {
279 rcm_log_message(RCM_ERROR
,
280 gettext("POOL: 'new_cpu_list' not found in nvlist: %s\n"),
285 if (nelem
!= new_total
) {
286 rcm_log_message(RCM_ERROR
,
287 gettext("POOL: 'new_cpu_list' size mismatch: %1$d vs "
288 "%2$d\n"), nelem
, new_total
);
293 for (i
= 0, removed_total
= 0; i
< old_total
; i
++) {
294 for (j
= 0; j
< new_total
; j
++)
295 if (old_cpu_list
[i
] == new_cpu_list
[j
])
297 if (j
== new_total
) /* not found in new_cpu_list */
298 removed_list
[removed_total
++] = old_cpu_list
[i
];
300 removed_list
[removed_total
] = -1;
302 if (removed_total
!= (old_total
- new_total
)) {
303 rcm_log_message(RCM_ERROR
,
304 gettext("POOL: error finding removed cpu list\n"));
308 if ((pvals
[0] = pool_value_alloc()) == NULL
) {
309 rcm_log_message(RCM_ERROR
, gettext("POOL: pool_value_alloc"
310 " failed: %s\n"), strerror(errno
));
315 * Look for resources with "'type' = 'pset'"
317 (void) pool_value_set_name(pvals
[0], "type");
318 (void) pool_value_set_string(pvals
[0], "pset");
319 if ((res
= pool_query_resources(conf
, &nelem
, pvals
)) == NULL
) {
320 rcm_log_message(RCM_ERROR
,
321 gettext("POOL: No psets found in configuration\n"));
322 pool_value_free(pvals
[0]);
326 pool_value_free(pvals
[0]);
327 for (i
= 0; res
[i
] != NULL
; i
++)
329 * Ask each pset if removing these cpus would cause it to go
330 * below it's minimum value.
332 if (pool_check_pset(conf
, res
[i
], removed_list
, errorp
) < 0) {
340 (void) pool_conf_close(conf
);
341 pool_conf_free(conf
);
345 * Set the error string if not already set.
347 if (error
!= RCM_SUCCESS
&& *errorp
== NULL
)
348 *errorp
= strdup(generic_error
);
353 * Returns RCM_SUCCESS in a number of error cases, since RCM_FAILURE would
354 * mean that the capacity change would be disallowed by this module,
355 * which is not what we mean.
358 pool_request_capacity_change(rcm_handle_t
*hdl
, char *rsrcname
, id_t id
,
359 uint_t flags
, nvlist_t
*nvlist
, char **errorp
, rcm_info_t
**dependent_info
)
364 rcm_log_message(RCM_TRACE1
,
365 "POOL: requesting capacity change for: %s (flag: %d)\n",
367 if (flags
& RCM_FORCE
) {
368 rcm_log_message(RCM_TRACE1
,
369 "POOL: Allowing forced operation to pass through...\n");
370 return (RCM_SUCCESS
);
372 for (i
= 0; registrations
[i
].rsrc
!= NULL
; i
++) {
373 if (strcmp(rsrcname
, registrations
[i
].rsrc
) == 0) {
374 return ((*registrations
[i
].capacity_change_cb
)(nvlist
,
379 return (RCM_SUCCESS
);
383 pool_notify_capacity_change(rcm_handle_t
*hdl
, char *rsrcname
, id_t id
,
384 uint_t flags
, nvlist_t
*nvlist
, char **info
, rcm_info_t
**dependent_info
)
386 rcm_log_message(RCM_TRACE1
,
387 "POOL: notifying capacity change for: %s (flags: %d)\n",
389 return (RCM_SUCCESS
);
393 pool_register(rcm_handle_t
*hdl
)
397 rcm_log_message(RCM_TRACE1
, "Registering Pools RCM module\n");
399 return (RCM_SUCCESS
);
401 for (i
= 0; registrations
[i
].rsrc
!= NULL
; i
++) {
402 if (rcm_register_capacity(hdl
, (char *)registrations
[i
].rsrc
,
403 0, NULL
) != RCM_SUCCESS
) {
404 rcm_log_message(RCM_ERROR
,
405 gettext("POOL: failed to register capacity "
406 "change for '%s'\n"),
407 registrations
[i
].rsrc
);
410 return (RCM_SUCCESS
);
414 pool_unregister(rcm_handle_t
*hdl
)
418 rcm_log_message(RCM_TRACE1
, "Pools RCM un-registered\n");
421 for (i
= 0; registrations
[i
].rsrc
!= NULL
; i
++)
422 if (rcm_unregister_capacity(hdl
,
423 (char *)registrations
[i
].rsrc
, 0) != RCM_SUCCESS
) {
424 rcm_log_message(RCM_ERROR
,
425 gettext("POOL: unregister capacity failed "
426 "for '%s'\n"), registrations
[i
].rsrc
);
429 return (RCM_SUCCESS
);
433 pool_get_info(rcm_handle_t
*hdl
, char *rsrcname
, id_t pid
, uint_t flag
,
434 char **infop
, char **errorp
, nvlist_t
*props
, rcm_info_t
**dependent_info
)
436 rcm_log_message(RCM_TRACE1
, "POOL: RCM get info: '%s'\n", rsrcname
);
437 if ((*infop
= strdup(gettext("POOL: In use by pool(4) subsystem")))
439 rcm_log_message(RCM_ERROR
, gettext("POOL: get info(%s) malloc "
440 "failure\n"), rsrcname
);
443 return (RCM_FAILURE
);
445 return (RCM_SUCCESS
);
450 pool_request_suspend(rcm_handle_t
*hdl
, char *rsrcname
,
451 id_t id
, timespec_t
*time
, uint_t flags
, char **reason
,
452 rcm_info_t
**dependent_info
)
454 rcm_log_message(RCM_TRACE1
,
455 "POOL: requesting suspend for: %s\n", rsrcname
);
456 return (RCM_SUCCESS
);
460 pool_notify_resume(rcm_handle_t
*hdl
, char *rsrcname
,
461 id_t pid
, uint_t flags
, char **reason
, rcm_info_t
**dependent_info
)
463 rcm_log_message(RCM_TRACE1
,
464 "POOL: notifying resume of: %s\n", rsrcname
);
465 return (RCM_SUCCESS
);
469 pool_request_offline(rcm_handle_t
*hdl
, char *rsrcname
, id_t pid
, uint_t flag
,
470 char **reason
, rcm_info_t
**dependent_info
)
472 rcm_log_message(RCM_TRACE1
,
473 "POOL: requesting offline for: %s\n", rsrcname
);
474 return (RCM_SUCCESS
);
478 pool_notify_online(rcm_handle_t
*hdl
, char *rsrcname
, id_t pid
, uint_t flags
,
479 char **reason
, rcm_info_t
**dependent_info
)
481 rcm_log_message(RCM_TRACE1
,
482 "POOL: notifying online for: %s\n", rsrcname
);
483 return (RCM_SUCCESS
);
486 pool_notify_remove(rcm_handle_t
*hdl
, char *rsrcname
, id_t pid
,
487 uint_t flag
, char **reason
, rcm_info_t
**dependent_info
)
489 rcm_log_message(RCM_TRACE1
,
490 "POOL: notifying removal of: %s\n", rsrcname
);
491 return (RCM_SUCCESS
);