diff --git a/src/plugins/select/bluegene/Makefile.am b/src/plugins/select/bluegene/Makefile.am index c1959e514f56a563dbed0c96d926cda46215eebe..f9073d8a91ae51fff9bb8da69075513be32a8ef3 100644 --- a/src/plugins/select/bluegene/Makefile.am +++ b/src/plugins/select/bluegene/Makefile.am @@ -25,13 +25,17 @@ select_bluegene_la_LDFLAGS = $(SO_LDFLAGS) $(PLUGIN_FLAGS) select_bluegene_la_LIBADD = $(top_builddir)/src/partition_allocator/libpartition_allocator.la -sbin_PROGRAMS = slurm_prolog slurm_epilog +sbin_PROGRAMS = slurm_prolog slurm_epilog sfree +sfree_LDADD = $(top_builddir)/src/common/libcommon.la \ + $(top_builddir)/src/api/libslurm.la slurm_prolog_LDADD = $(top_builddir)/src/common/libcommon.la \ $(top_builddir)/src/api/libslurm.la slurm_epilog_LDADD = $(top_builddir)/src/common/libcommon.la \ $(top_builddir)/src/api/libslurm.la +sfree_SOURCES = sfree.c sfree.h opts.c slurm_prolog_SOURCES = slurm_prolog.c slurm_epilog_SOURCES = slurm_epilog.c +sfree_LDFLAGS = -export-dynamic -lm $(CMD_LDFLAGS) $(BGL_LDFLAGS) slurm_prolog_LDFLAGS = -export-dynamic $(CMD_LDFLAGS) slurm_epilog_LDFLAGS = -export-dynamic $(CMD_LDFLAGS) diff --git a/src/plugins/select/bluegene/opts.c b/src/plugins/select/bluegene/opts.c new file mode 100644 index 0000000000000000000000000000000000000000..a69418f0775b23b8c09b201ba8a422a388e08f1e --- /dev/null +++ b/src/plugins/select/bluegene/opts.c @@ -0,0 +1,127 @@ +/****************************************************************************\ + * opts.c - sfree command line option processing functions + ***************************************************************************** + * Copyright (C) 2002 The Regents of the University of California. + * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). + * Written by Danny Auble <da@llnl.gov> + * UCRL-CODE-2002-040. + * + * This file is part of SLURM, a resource management program. + * For details, see <http://www.llnl.gov/linux/slurm/>. + * + * SLURM is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * SLURM is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along + * with SLURM; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +\*****************************************************************************/ + +#include "sfree.h" + +/* FUNCTIONS */ +static void _help(void); +static void _print_version(void); +static void _usage(void); + +/* + * parse_command_line, fill in params data structure with data + */ +void parse_command_line(int argc, char *argv[]) +{ + int opt_char; + int option_index; + + static struct option long_options[] = { + {"all", required_argument, 0, 'a'}, + {"partition", no_argument, 0, 'p'}, + {"version", no_argument, 0, 'V'}, + {"help", no_argument, 0, 'h'}, + {"usage", no_argument, 0, 'u'}, + {NULL, 0, 0, 0} + }; + + while ((opt_char = + getopt_long(argc, argv, "ahup:V", + long_options, &option_index)) != -1) { + switch (opt_char) { + case (int) '?': + fprintf(stderr, + "Try \"sfree --help\" for more information\n"); + exit(1); + break; + case (int) 'a': + all_parts = 1; + break; + case (int) 'V': + _print_version(); + exit(0); + case (int) 'p': + bgl_part_id = optarg; + break; + case (int) 'h': + case (int) OPT_LONG_HELP: + _help(); + exit(0); + case (int) 'u': + case (int) OPT_LONG_USAGE: + _usage(); + exit(0); + } + } + +} + +void snprint_time(char *buf, size_t buf_size, time_t time) +{ + if (time == INFINITE) { + snprintf(buf, buf_size, "UNLIMITED"); + } else { + long days, hours, minutes, seconds; + seconds = time % 60; + minutes = (time / 60) % 60; + hours = (time / 3600) % 24; + days = time / 86400; + + if (days) + snprintf(buf, buf_size, + "%ld:%2.2ld:%2.2ld:%2.2ld", + days, hours, minutes, seconds); + else if (hours) + snprintf(buf, buf_size, + "%ld:%2.2ld:%2.2ld", + hours, minutes, seconds); + else + snprintf(buf, buf_size, + "%ld:%2.2ld", minutes,seconds); + } +} + +static void _print_version(void) +{ + printf("%s %s\n", PACKAGE, SLURM_VERSION); +} + +static void _usage(void) +{ + printf("Usage: sfree [-huVca] [-p]\n"); +} + +static void _help(void) +{ + printf("\ +Usage: sfree [OPTIONS]\n\ + -p, --partition free specific partition named\n\ + -a, --all free all partitions\n\ + -V, --version output version information and exit\n\ +\nHelp options:\n\ + --help show this help message\n\ + --usage display brief usage message\n"); +} diff --git a/src/plugins/select/bluegene/sfree.c b/src/plugins/select/bluegene/sfree.c new file mode 100644 index 0000000000000000000000000000000000000000..4f4b13ef86f4a5e4ea65577c5e8737ec909340ad --- /dev/null +++ b/src/plugins/select/bluegene/sfree.c @@ -0,0 +1,431 @@ +/*****************************************************************************\ + * sfree.c - free specified partition or all partitions. + ***************************************************************************** + * Copyright (C) 2004 The Regents of the University of California. + * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). + * Written by Danny Auble <da@llnl.gov> + * + * UCRL-CODE-2002-040. + * + * This file is part of SLURM, a resource management program. + * For details, see <http://www.llnl.gov/linux/slurm/>. + * + * SLURM is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * SLURM is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along + * with SLURM; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +\*****************************************************************************/ + +#include "sfree.h" + +#define MAX_POLL_RETRIES 110 +#define POLL_INTERVAL 3 + +/************ + * Functions * + ************/ +#ifdef HAVE_BGL_FILES + +char *bgl_part_id = NULL; +int all_parts = 0; + +static int _free_partition(char *bgl_part_id); +static int _update_bgl_record_state(char *bgl_part_id); +static void _term_jobs_on_part(char *bgl_part_id); +static char *_bgl_err_str(status_t inx); +static int _remove_job(db_job_id_t job_id); + +int main(int argc, char *argv[]) +{ + log_options_t opts = LOG_OPTS_STDERR_ONLY; + rm_partition_list_t *part_list = NULL; + rm_partition_state_flag_t part_state = PARTITION_ALL_FLAG; + int j, num_parts = 0; + rm_partition_t *part_ptr = NULL; + int rc; + + log_init(xbasename(argv[0]), opts, SYSLOG_FACILITY_DAEMON, NULL); + parse_command_line(argc, argv); + if(!all_parts) { + if(!bgl_part_id) { + error("you need to specify a partition"); + exit(0); + } + _free_partition(bgl_part_id); + } else { + if ((rc = rm_get_partitions_info(part_state, &part_list)) + != STATUS_OK) { + error("rm_get_partitions_info(): %s", _bgl_err_str(rc)); + return -1; + } + + if ((rc = rm_get_data(part_list, RM_PartListSize, &num_parts)) + != STATUS_OK) { + error("rm_get_data(RM_PartListSize): %s", + _bgl_err_str(rc)); + + num_parts = 0; + } + + for (j=0; j<num_parts; j++) { + if (j) { + if ((rc = rm_get_data(part_list, + RM_PartListNextPart, + &part_ptr)) + != STATUS_OK) { + error("rm_get_data" + "(RM_PartListNextPart): %s", + _bgl_err_str(rc)); + + break; + } + } else { + if ((rc = rm_get_data(part_list, + RM_PartListFirstPart, + &part_ptr)) + != STATUS_OK) { + error("rm_get_data" + "(RM_PartListFirstPart: %s", + _bgl_err_str(rc)); + + break; + } + } + if ((rc = rm_get_data(part_ptr, RM_PartitionID, + &bgl_part_id)) + != STATUS_OK) { + error("rm_get_data(RM_PartitionID): %s", + _bgl_err_str(rc)); + + break; + } + if(strncmp("RMP", bgl_part_id, 3)) + continue; + _free_partition(bgl_part_id); + } + if ((rc = rm_free_partition_list(part_list)) != STATUS_OK) { + error("rm_free_partition_list(): %s", + _bgl_err_str(rc)); + } + } + return 0; +} + +static int _free_partition(char *bgl_part_id) +{ + int state=-1; + int rc; + + info("freeing partition %s", bgl_part_id); + _term_jobs_on_part(bgl_part_id); + while (1) { + if((state = _update_bgl_record_state(bgl_part_id)) + == SLURM_ERROR) + break; + if (state != RM_PARTITION_FREE + && state != RM_PARTITION_DEALLOCATING) { + info("pm_destroy %s",bgl_part_id); + if ((rc = pm_destroy_partition(bgl_part_id)) + != STATUS_OK) { + if(rc == PARTITION_NOT_FOUND) { + info("partition %s is not found"); + break; + } + error("pm_destroy_partition(%s): %s", + bgl_part_id, + _bgl_err_str(rc)); + } + } + + if ((state == RM_PARTITION_FREE) + || (state == RM_PARTITION_ERROR)) + break; + sleep(3); + } + info("partition %s is freed", bgl_part_id); + return SLURM_SUCCESS; +} + +static int _update_bgl_record_state(char *bgl_part_id) +{ + rm_partition_state_flag_t part_state = PARTITION_ALL_FLAG; + char *name = NULL; + rm_partition_list_t *part_list = NULL; + int j, rc, num_parts = 0; + rm_partition_state_t state = -1; + rm_partition_t *part_ptr = NULL; + + if ((rc = rm_get_partitions_info(part_state, &part_list)) + != STATUS_OK) { + error("rm_get_partitions_info(): %s", _bgl_err_str(rc)); + return -1; + } + + if ((rc = rm_get_data(part_list, RM_PartListSize, &num_parts)) + != STATUS_OK) { + error("rm_get_data(RM_PartListSize): %s", _bgl_err_str(rc)); + state = -1; + num_parts = 0; + } + + for (j=0; j<num_parts; j++) { + if (j) { + if ((rc = rm_get_data(part_list, + RM_PartListNextPart, + &part_ptr)) + != STATUS_OK) { + error("rm_get_data(RM_PartListNextPart): %s", + _bgl_err_str(rc)); + state = -1; + break; + } + } else { + if ((rc = rm_get_data(part_list, + RM_PartListFirstPart, + &part_ptr)) + != STATUS_OK) { + error("rm_get_data(RM_PartListFirstPart: %s", + _bgl_err_str(rc)); + state = -1; + break; + } + } + if ((rc = rm_get_data(part_ptr, + RM_PartitionID, + &name)) + != STATUS_OK) { + error("rm_get_data(RM_PartitionID): %s", + _bgl_err_str(rc)); + state = -1; + break; + } + if(!strcmp(bgl_part_id, name)) + break; + } + + if(state == -1) + goto clean_up; + else if(j>=num_parts) { + error("This partition, %s, doesn't exist in MMCS", + bgl_part_id); + state = -1; + goto clean_up; + } + + if ((rc = rm_get_data(part_ptr, + RM_PartitionState, + &state)) + != STATUS_OK) { + error("rm_get_data(RM_PartitionState): %s", + _bgl_err_str(rc)); + } + +clean_up: + if ((rc = rm_free_partition_list(part_list)) != STATUS_OK) { + error("rm_free_partition_list(): %s", _bgl_err_str(rc)); + } + return state; +} + +/* Perform job termination work */ +static void _term_jobs_on_part(char *bgl_part_id) +{ + int i, jobs, rc, job_found = 0; + rm_job_list_t *job_list; + int live_states; + rm_element_t *job_elem; + pm_partition_id_t part_id; + db_job_id_t job_id; + + //debug("getting the job info"); + live_states = JOB_ALL_FLAG + & (~JOB_TERMINATED_FLAG) + & (~JOB_KILLED_FLAG); + if ((rc = rm_get_jobs(live_states, &job_list)) != STATUS_OK) { + error("rm_get_jobs(): %s", _bgl_err_str(rc)); + return; + } + + if ((rc = rm_get_data(job_list, RM_JobListSize, &jobs)) != STATUS_OK) { + error("rm_get_data(RM_JobListSize): %s", _bgl_err_str(rc)); + jobs = 0; + } else if (jobs > 300) + fatal("Active job count (%d) invalid, restart MMCS", jobs); + //debug("job count %d",jobs); + for (i=0; i<jobs; i++) { + if (i) { + if ((rc = rm_get_data(job_list, RM_JobListNextJob, + &job_elem)) != STATUS_OK) { + error("rm_get_data(RM_JobListNextJob): %s", + _bgl_err_str(rc)); + continue; + } + } else { + if ((rc = rm_get_data(job_list, RM_JobListFirstJob, + &job_elem)) != STATUS_OK) { + error("rm_get_data(RM_JobListFirstJob): %s", + _bgl_err_str(rc)); + continue; + } + } + + if(!job_elem) { + error("No Job Elem breaking out job count = %d\n", + jobs); + break; + } + if ((rc = rm_get_data(job_elem, RM_JobPartitionID, &part_id)) + != STATUS_OK) { + error("rm_get_data(RM_JobPartitionID) %s: %s", + part_id, _bgl_err_str(rc)); + continue; + } + + if (strcmp(part_id, bgl_part_id) != 0) + continue; + job_found = 1; + if ((rc = rm_get_data(job_elem, RM_JobDBJobID, &job_id)) + != STATUS_OK) { + error("rm_get_data(RM_JobDBJobID): %s", + _bgl_err_str(rc)); + continue; + } + info("got job_id %d",job_id); + if((rc = _remove_job(job_id)) + == INTERNAL_ERROR) + goto not_removed; + + } + if(job_found == 0) + info("No jobs on partition"); + +not_removed: + if ((rc = rm_free_job_list(job_list)) != STATUS_OK) + error("rm_free_job_list(): %s", _bgl_err_str(rc)); +} + +/* + * Convert a BGL API error code to a string + * IN inx - error code from any of the BGL Bridge APIs + * RET - string describing the error condition + */ +static char *_bgl_err_str(status_t inx) +{ + switch (inx) { + case STATUS_OK: + return "Status OK"; + case PARTITION_NOT_FOUND: + return "Partition not found"; + case JOB_NOT_FOUND: + return "Job not found"; + case BP_NOT_FOUND: + return "Base partition not found"; + case SWITCH_NOT_FOUND: + return "Switch not found"; + case JOB_ALREADY_DEFINED: + return "Job already defined"; + case CONNECTION_ERROR: + return "Connection error"; + case INTERNAL_ERROR: + return "Internal error"; + case INVALID_INPUT: + return "Invalid input"; + case INCOMPATIBLE_STATE: + return "Incompatible state"; + case INCONSISTENT_DATA: + return "Inconsistent data"; + } + return "?"; +} + +/* Kill a job and remove its record from MMCS */ +static int _remove_job(db_job_id_t job_id) +{ + int i, rc; + rm_job_t *job_rec = NULL; + rm_job_state_t job_state; + + info("removing job %d from MMCS", job_id); + for (i=0; i<MAX_POLL_RETRIES; i++) { + if (i > 0) + sleep(POLL_INTERVAL); + + /* Find the job */ + if ((rc = rm_get_job(job_id, &job_rec)) != STATUS_OK) { + if (rc == JOB_NOT_FOUND) { + debug("job %d removed from MMCS", job_id); + return STATUS_OK; + } + + error("rm_get_job(%d): %s", job_id, + _bgl_err_str(rc)); + continue; + } + + if ((rc = rm_get_data(job_rec, RM_JobState, &job_state)) != + STATUS_OK) { + (void) rm_free_job(job_rec); + if (rc == JOB_NOT_FOUND) { + debug("job %d not found in MMCS", job_id); + return STATUS_OK; + } + + error("rm_get_data(RM_JobState) for jobid=%d " + "%s", job_id, _bgl_err_str(rc)); + continue; + } + if ((rc = rm_free_job(job_rec)) != STATUS_OK) + error("rm_free_job: %s", _bgl_err_str(rc)); + + info("job %d is in state %d", job_id, job_state); + + /* check the state and process accordingly */ + if(job_state == RM_JOB_TERMINATED) + return STATUS_OK; + else if(job_state == RM_JOB_DYING) + continue; + else if(job_state == RM_JOB_ERROR) { + error("job %d is in a error state.", job_id); + + //free_bgl_partition(); + return STATUS_OK; + } else { + (void) jm_signal_job(job_id, SIGKILL); + rc = jm_cancel_job(job_id); + } + + if (rc != STATUS_OK) { + if (rc == JOB_NOT_FOUND) { + debug("job %d removed from MMCS", job_id); + return STATUS_OK; + } + if(rc == INCOMPATIBLE_STATE) + debug("job %d is in an INCOMPATIBLE_STATE", + job_id); + else + error("rm_cancel_job(%d): %s", job_id, + _bgl_err_str(rc)); + } + } + error("Failed to remove job %d from MMCS", job_id); + return INTERNAL_ERROR; +} + +#else + +int main(int argc, char *argv[]) +{ + printf("Only can be ran on the service node of a BGL system.\n"); + return 0; +} + +#endif diff --git a/src/plugins/select/bluegene/sfree.h b/src/plugins/select/bluegene/sfree.h new file mode 100644 index 0000000000000000000000000000000000000000..8b830d46d5d5349fae8999d5b9cbf826b6e22d77 --- /dev/null +++ b/src/plugins/select/bluegene/sfree.h @@ -0,0 +1,51 @@ +/****************************************************************************\ + * sfree.h - definitions used for sfree data functions + ***************************************************************************** + * Copyright (C) 2004 The Regents of the University of California. + * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). + * Written by Danny Auble <da@llnl.gov> + * UCRL-CODE-2002-040. + * + * This file is part of SLURM, a resource management program. + * For details, see <http://www.llnl.gov/linux/slurm/>. + * + * SLURM is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * SLURM is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along + * with SLURM; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +\****************************************************************************/ + +#ifndef _SFREE_H +#define _SFREE_H + +#if HAVE_GETOPT_H +# include <getopt.h> +#else +# include "src/common/getopt.h" +#endif + +#include <signal.h> +#include "bluegene.h" + +/* getopt_long options, integers but not characters */ +#define OPT_LONG_HELP 0x100 +#define OPT_LONG_USAGE 0x101 +#define OPT_LONG_HIDE 0x102 + +typedef void (*sighandler_t) (int); + +extern char *bgl_part_id; +extern int all_parts; + +extern void parse_command_line(int argc, char *argv[]); + +#endif