From 80875b329a171cf624c47e83a31ea236fd8ae621 Mon Sep 17 00:00:00 2001
From: Moe Jette <jette1@llnl.gov>
Date: Fri, 23 Jan 2009 19:00:32 +0000
Subject: [PATCH] Add basic infrastructure for resource reservation. Still
 under development svn m_e_r_g_e -r16224:16292
 https://eris.llnl.gov/svn/slurm/branches/slurm-1.4.resv

---
 slurm/slurm.h.in                 |  162 +++-
 slurm/slurm_errno.h              |    1 +
 src/api/Makefile.am              |    1 +
 src/api/Makefile.in              |    8 +-
 src/api/init_msg.c               |   25 +-
 src/api/reservation_info.c       |  199 +++++
 src/api/update_config.c          |   80 +-
 src/common/slurm_errno.c         |    2 +
 src/common/slurm_protocol_defs.c |   85 +-
 src/common/slurm_protocol_defs.h |   19 +-
 src/common/slurm_protocol_pack.c |  257 +++++-
 src/scontrol/Makefile.am         |    2 +
 src/scontrol/Makefile.in         |    8 +-
 src/scontrol/create_res.c        |  310 +++++++
 src/scontrol/info_part.c         |    2 +-
 src/scontrol/info_res.c          |  139 ++++
 src/scontrol/scontrol.c          |   59 +-
 src/scontrol/scontrol.h          |    4 +
 src/scontrol/update_part.c       |  169 ++--
 src/slurmctld/partition_mgr.c    |    8 +-
 src/slurmctld/proc_req.c         |  222 +++++-
 src/slurmctld/read_config.c      |    2 +
 src/slurmctld/reservation.c      | 1286 +++++++++++++++++++++++++++++-
 src/slurmctld/reservation.h      |   34 +-
 src/slurmctld/slurmctld.h        |    2 +-
 src/slurmctld/state_save.c       |   27 +-
 src/slurmctld/state_save.h       |    6 +-
 27 files changed, 2989 insertions(+), 130 deletions(-)
 create mode 100644 src/api/reservation_info.c
 create mode 100644 src/scontrol/create_res.c
 create mode 100644 src/scontrol/info_res.c

diff --git a/slurm/slurm.h.in b/slurm/slurm.h.in
index 69565e663c6..69322c6d8ca 100644
--- a/slurm/slurm.h.in
+++ b/slurm/slurm.h.in
@@ -956,6 +956,57 @@ typedef struct partition_info_msg {
 	partition_info_t *partition_array; /* the partition records */
 } partition_info_msg_t;
 
+/*
+ * Resource reservation data structures.
+ * Create, show, modify and delete functions are required
+ */
+#define RESERVE_TYPE_MAINT	0x0001
+
+typedef struct reserve_info {
+	char *name;		/* name of reservation */
+	time_t start_time;	/* start time of reservation */
+	time_t end_time;	/* end time of reservation */
+	uint16_t type;		/* see RESERVE_TYPE_* above */
+	uint32_t node_cnt;	/* count of nodes required */
+	char *node_list;	/* list of reserved nodes or ALL */
+	char *features;		/* required node features */
+	char *partition;	/* name of partition to be used */
+/* Access control specification for the reservation */
+	char *users;		/* names of users permitted to use */
+	char *accounts;		/* names of accounts permitted to use */
+} reserve_info_t;
+
+typedef struct reserve_info_msg {
+	time_t last_update;	/* time of latest info */
+	uint32_t record_count;	/* number of records */
+	reserve_info_t *reservation_array; /* the reservation records */
+} reserve_info_msg_t;
+
+typedef struct reserve_request_msg {
+	char *name;		/* name of reservation */
+	time_t start_time;	/* start time of reservation */
+	time_t end_time;	/* end time of reservation */
+	uint32_t duration;	/* duration of reservation in seconds */
+	uint16_t type;		/* see RESERVE_TYPE_* above */
+	uint32_t node_cnt;	/* count of nodes required */
+	char *node_list;	/* list of reserved nodes or ALL */
+	char *features;		/* required node features */
+	char *partition;	/* name of partition to be used */
+/* Access control specification for the reservation */
+	char *users;		/* names of users permitted to use */
+	char *accounts;		/* names of accounts permitted to use */
+} reserve_request_msg_t;
+
+typedef struct reserve_response_msg {
+	char *name;		/* name of reservation */
+} reserve_response_msg_t;
+
+typedef struct reservation_name_msg {
+	char *name;		/* name of reservation just created or
+				 * to be delete */
+} reservation_name_msg_t;
+
+
 #define DEBUG_FLAG_SELECT_TYPE	0x00000001	/* SelectType plugin */
 #define DEBUG_FLAG_STEPS	0x00000002	/* slurmctld steps */
 #define DEBUG_FLAG_TRIGGERS	0x00000004	/* slurmctld triggers */
@@ -964,12 +1015,12 @@ typedef struct partition_info_msg {
 typedef struct slurm_ctl_conf {
 	time_t last_update;	/* last update time of the build parameters */
 	uint16_t accounting_storage_enforce; /* job requires valid association:
-					* user/account/partition/cluster */
-	char *accounting_storage_host; /* accounting storage host */
-	char *accounting_storage_loc; /* accounting storage (db table)
-				       * location */
-	char *accounting_storage_pass; /* accounting storage
-					    password */
+					 * user/account/partition/cluster */
+	char *accounting_storage_host;	/* accounting storage host */
+	char *accounting_storage_loc;	/* accounting storage (db table)
+					 * location */
+	char *accounting_storage_pass;	/* accounting storage
+					 * password */
 	uint32_t accounting_storage_port;/* node accountinging storage port */
 	char *accounting_storage_type; /* accounting storage type */
 	char *accounting_storage_user; /* accounting storage user */
@@ -1855,7 +1906,7 @@ extern int slurm_update_node PARAMS(( update_node_msg_t * node_msg ));
 /* 
  * slurm_init_part_desc_msg - initialize partition descriptor with 
  *	default values 
- * OUT job_desc_msg - user defined partition descriptor
+ * IN/OUT update_part_msg - user defined partition descriptor
  */
 extern void slurm_init_part_desc_msg PARAMS((update_part_msg_t * update_part_msg ));
 
@@ -1912,6 +1963,14 @@ extern void slurm_print_partition_info PARAMS((
  */
 extern char *slurm_sprint_partition_info PARAMS(( 
 		partition_info_t * part_ptr, int one_liner ));
+
+/*
+ * slurm_create_partition - create a new partition, only usable by user root
+ * IN part_msg - description of partition configuration
+ * RET 0 on success, otherwise return -1 and set errno to indicate the error
+ */
+extern int slurm_create_partition PARAMS(( update_part_msg_t * part_msg ));
+
 /*
  * slurm_update_partition - issue RPC to update a partition's configuration
  *	per request, only usable by user root
@@ -1928,6 +1987,95 @@ extern int slurm_update_partition PARAMS(( update_part_msg_t * part_msg ));
  */
 extern int slurm_delete_partition PARAMS(( delete_part_msg_t * part_msg ));
 
+/*****************************************************************************\
+ *	SLURM PARTITION CONFIGURATION READ/PRINT/UPDATE FUNCTIONS
+\*****************************************************************************/
+
+/*
+ * slurm_init_resv_desc_msg - initialize reservation descriptor with 
+ *	default values 
+ * OUT job_desc_msg - user defined partition descriptor
+ */
+extern void slurm_init_resv_desc_msg PARAMS(( 
+		reserve_request_msg_t * update_resv_msg ));
+/*
+ * slurm_create_reservation - create a new reservation, only usable by user root
+ * IN resv_msg - description of reservation
+ * RET name of reservation on success (caller must free the memory),
+ *	otherwise return NULL and set errno to indicate the error
+ */
+extern char * slurm_create_reservation PARAMS((
+		reserve_request_msg_t * resv_msg ));
+
+/*
+ * slurm_update_reservation - modify an existing reservation, only usable by 
+ *	user root
+ * IN resv_msg - description of reservation
+ * RET 0 on success, otherwise return -1 and set errno to indicate the error
+ */
+extern int slurm_update_reservation PARAMS((reserve_request_msg_t * resv_msg));
+
+/*
+ * slurm_delete_reservation - issue RPC to delete a reservation, only usable 
+ *	by user root
+ * IN resv_msg - description of reservation to delete
+ * RET 0 on success, otherwise return -1 and set errno to indicate the error
+ */
+extern int slurm_delete_reservation PARAMS(( 
+		reservation_name_msg_t * resv_msg ));
+
+/*
+ * slurm_load_reservations - issue RPC to get all slurm reservation 
+ *	configuration information if changed since update_time 
+ * IN update_time - time of current configuration data
+ * IN reserve_info_msg_pptr - place to store a reservation configuration 
+ *	pointer
+ * RET 0 or a slurm error code
+ * NOTE: free the response using slurm_free_reservation_info_msg
+ */
+extern int slurm_load_reservations PARAMS(( time_t update_time, 
+		reserve_info_msg_t **resp ));
+
+/*
+ * slurm_print_reservation_info_msg - output information about all Slurm 
+ *	reservations based upon message as loaded using slurm_load_reservation
+ * IN out - file to write to
+ * IN resv_info_ptr - reservation information message pointer
+ * IN one_liner - print as a single line if true
+ */
+void slurm_print_reservation_info_msg PARAMS(( FILE* out, 
+		reserve_info_msg_t * resv_info_ptr, int one_liner ));
+
+/*
+ * slurm_print_reservation_info - output information about a specific Slurm 
+ *	reservation based upon message as loaded using slurm_load_reservation
+ * IN out - file to write to
+ * IN resv_ptr - an individual reservation information record pointer
+ * IN one_liner - print as a single line if true
+ */
+void slurm_print_reservation_info PARAMS(( FILE* out, 
+		reserve_info_t * resv_ptr, int one_liner ));
+
+/*
+ * slurm_sprint_reservation_info - output information about a specific Slurm 
+ *	reservation based upon message as loaded using slurm_load_reservations
+ * IN resv_ptr - an individual reservation information record pointer
+ * IN one_liner - print as a single line if true
+ * RET out - char * containing formatted output (must be freed after call)
+ *           NULL is returned on failure.
+ */
+char *slurm_sprint_reservation_info PARAMS(( reserve_info_t * resv_ptr, 
+		int one_liner ));
+
+/*
+ * slurm_free_reservation_info_msg - free the reservation information 
+ *	response message
+ * IN msg - pointer to reservation information response message
+ * NOTE: buffer is loaded by slurm_load_reservation
+ */
+extern void slurm_free_reservation_info_msg PARAMS(( 
+	reserve_info_msg_t * resv_info_ptr ));
+
 /*****************************************************************************\
  *	SLURM PING/RECONFIGURE/SHUTDOWN FUNCTIONS
 \*****************************************************************************/
diff --git a/slurm/slurm_errno.h b/slurm/slurm_errno.h
index 6ab77838ab6..e66498fe430 100644
--- a/slurm/slurm_errno.h
+++ b/slurm/slurm_errno.h
@@ -161,6 +161,7 @@ enum {
 	ESLURM_INVALID_TIME_LIMIT,
 	ESLURM_RESERVATION_ACCESS,
 	ESLURM_RESERVATION_INVALID,
+	ESLURM_INVALID_TIME_VALUE,
 
 	/* switch specific error codes, specific values defined in plugin module */
 	ESLURM_SWITCH_MIN = 3000,
diff --git a/src/api/Makefile.am b/src/api/Makefile.am
index 0000a85496a..ef5543cba7a 100644
--- a/src/api/Makefile.am
+++ b/src/api/Makefile.am
@@ -76,6 +76,7 @@ slurmapi_src =           \
 	node_info.c      \
 	node_select_info.c node_select_info.h \
 	partition_info.c \
+	reservation_info.c \
 	signal.c         \
 	slurm_pmi.c slurm_pmi.h	\
 	step_ctx.c step_ctx.h \
diff --git a/src/api/Makefile.in b/src/api/Makefile.in
index 55ef23745d0..ce861a4f972 100644
--- a/src/api/Makefile.in
+++ b/src/api/Makefile.in
@@ -100,9 +100,9 @@ libslurmhelper_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
 am__objects_1 = allocate.lo allocate_msg.lo cancel.lo checkpoint.lo \
 	complete.lo config_info.lo init_msg.lo job_info.lo \
 	job_step_info.lo node_info.lo node_select_info.lo \
-	partition_info.lo signal.lo slurm_pmi.lo step_ctx.lo \
-	step_io.lo step_launch.lo pmi_server.lo submit.lo suspend.lo \
-	triggers.lo reconfigure.lo update_config.lo
+	partition_info.lo reservation_info.lo signal.lo slurm_pmi.lo \
+	step_ctx.lo step_io.lo step_launch.lo pmi_server.lo submit.lo \
+	suspend.lo triggers.lo reconfigure.lo update_config.lo
 am_libslurmhelper_la_OBJECTS = $(am__objects_1)
 libslurmhelper_la_OBJECTS = $(am_libslurmhelper_la_OBJECTS)
 PROGRAMS = $(noinst_PROGRAMS)
@@ -371,6 +371,7 @@ slurmapi_src = \
 	node_info.c      \
 	node_select_info.c node_select_info.h \
 	partition_info.c \
+	reservation_info.c \
 	signal.c         \
 	slurm_pmi.c slurm_pmi.h	\
 	step_ctx.c step_ctx.h \
@@ -536,6 +537,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pmi.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pmi_server.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reconfigure.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reservation_info.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/signal.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/slurm_pmi.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/step_ctx.Plo@am__quote@
diff --git a/src/api/init_msg.c b/src/api/init_msg.c
index 95d9ea6187d..b23c73eac16 100644
--- a/src/api/init_msg.c
+++ b/src/api/init_msg.c
@@ -2,7 +2,7 @@
  *  init_msg.c - initialize RPC messages contents
  *****************************************************************************
  *  Copyright (C) 2002-2007 The Regents of the University of California.
- *  Copyright (C) 2008 Lawrence Livermore National Security.
+ *  Copyright (C) 2008-2009 Lawrence Livermore National Security.
  *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
  *  Written by Morris Jette <jette1@llnl.gov>.
  *  LLNL-CODE-402394.
@@ -51,7 +51,7 @@
 /*
  * slurm_init_job_desc_msg - initialize job descriptor with 
  *	default values 
- * OUT job_desc_msg - user defined job descriptor
+ * IN/OUT job_desc_msg - user defined job descriptor
  */
 void slurm_init_job_desc_msg(job_desc_msg_t * job_desc_msg)
 {
@@ -144,7 +144,7 @@ void slurm_init_job_desc_msg(job_desc_msg_t * job_desc_msg)
 /*
  * slurm_init_part_desc_msg - initialize partition descriptor with 
  *	default values 
- * OUT job_desc_msg - user defined partition descriptor
+ * IN/OUT update_part_msg - user defined partition descriptor
  */
 void slurm_init_part_desc_msg (update_part_msg_t * update_part_msg)
 {
@@ -162,3 +162,22 @@ void slurm_init_part_desc_msg (update_part_msg_t * update_part_msg)
 	update_part_msg->state_up 	= (uint16_t) NO_VAL;
 }
 
+/*
+ * slurm_init_resv_desc_msg - initialize reservation descriptor with 
+ *	default values 
+ * OUT job_desc_msg - user defined partition descriptor
+ */
+void slurm_init_resv_desc_msg (reserve_request_msg_t * update_resv_msg)
+{
+	update_resv_msg->name		= NULL;
+	update_resv_msg->start_time	= (time_t) NO_VAL;
+	update_resv_msg->end_time	= (time_t) NO_VAL;
+	update_resv_msg->duration	= NO_VAL;
+	update_resv_msg->type		= (uint16_t) NO_VAL;
+	update_resv_msg->node_cnt	= NO_VAL;
+	update_resv_msg->node_list	= NULL;
+	update_resv_msg->features	= NULL;
+	update_resv_msg->partition	= NULL;
+	update_resv_msg->users		= NULL;
+	update_resv_msg->accounts	= NULL;
+}
diff --git a/src/api/reservation_info.c b/src/api/reservation_info.c
new file mode 100644
index 00000000000..50bd390f4c1
--- /dev/null
+++ b/src/api/reservation_info.c
@@ -0,0 +1,199 @@
+/*****************************************************************************\
+ *  reseration_info.c - get/print the reservation state information of slurm
+ *****************************************************************************
+ *  Copyright (C) 2009 Lawrence Livermore National Security.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Morris Jette <jette1@llnl.gov> et. al.
+ *  LLNL-CODE-402394.
+ *   
+ *  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.
+ *
+ *  In addition, as a special exception, the copyright holders give permission 
+ *  to link the code of portions of this program with the OpenSSL library under 
+ *  certain conditions as described in each individual source file, and 
+ *  distribute linked combinations including the two. You must obey the GNU 
+ *  General Public License in all respects for all of the code used other than 
+ *  OpenSSL. If you modify file(s) with this exception, you may extend this 
+ *  exception to your version of the file(s), but you are not obligated to do 
+ *  so. If you do not wish to do so, delete this exception statement from your
+ *  version.  If you delete this exception statement from all source files in 
+ *  the program, then also delete it here.
+ *  
+ *  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.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA.
+\*****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <slurm/slurm.h>
+
+#include "src/api/job_info.h"
+#include "src/common/parse_time.h"
+#include "src/common/slurm_protocol_api.h"
+#include "src/common/xmalloc.h"
+#include "src/common/xstring.h"
+
+/*
+ * slurm_print_reservation_info_msg - output information about all Slurm 
+ *	reservations based upon message as loaded using slurm_load_reservation
+ * IN out - file to write to
+ * IN resv_info_ptr - reservation information message pointer
+ * IN one_liner - print as a single line if true
+ */
+void slurm_print_reservation_info_msg ( FILE* out, 
+		reserve_info_msg_t * resv_info_ptr, int one_liner )
+{
+	int i ;
+	reserve_info_t * resv_ptr = resv_info_ptr->reservation_array ;
+	char time_str[32];
+
+	slurm_make_time_str( (time_t *)&resv_info_ptr->last_update, time_str, 
+			     sizeof(time_str));
+	fprintf( out, "Reservation data as of %s, record count %d\n",
+		time_str, resv_info_ptr->record_count);
+
+	for (i = 0; i < resv_info_ptr->record_count; i++) {
+		slurm_print_reservation_info ( out, & resv_ptr[i], one_liner );
+	}
+
+}
+
+/*
+ * slurm_print_reservation_info - output information about a specific Slurm 
+ *	reservation based upon message as loaded using slurm_load_reservation
+ * IN out - file to write to
+ * IN resv_ptr - an individual reservation information record pointer
+ * IN one_liner - print as a single line if true
+ */
+void slurm_print_reservation_info ( FILE* out, reserve_info_t * resv_ptr, 
+				    int one_liner )
+{
+	char *print_this = slurm_sprint_reservation_info(resv_ptr, one_liner);
+	fprintf ( out, "%s", print_this);
+	xfree(print_this);
+}
+
+
+/*
+ * slurm_sprint_reservation_info - output information about a specific Slurm 
+ *	reservation based upon message as loaded using slurm_load_reservations
+ * IN resv_ptr - an individual reservation information record pointer
+ * IN one_liner - print as a single line if true
+ * RET out - char * containing formatted output (must be freed after call)
+ *           NULL is returned on failure.
+ */
+char *slurm_sprint_reservation_info ( reserve_info_t * resv_ptr, 
+				      int one_liner )
+{
+	char tmp1[32], tmp2[32], *tmp3;
+	char tmp_line[MAXHOSTRANGELEN];
+	char *out = NULL;
+
+	/****** Line 1 ******/
+	slurm_make_time_str(&resv_ptr->start_time, tmp1, sizeof(tmp1));
+	slurm_make_time_str(&resv_ptr->end_time,   tmp2, sizeof(tmp2));
+	snprintf(tmp_line, sizeof(tmp_line),
+		 "ReservationName=%s StartTime=%s EndTime=%s Duration=%u",
+		 resv_ptr->name, tmp1, tmp2, 
+		 (uint32_t) (difftime(resv_ptr->end_time, 
+				      resv_ptr->start_time) / 60));
+	xstrcat(out, tmp_line);
+
+	if (one_liner)
+		xstrcat(out, " ");
+	else
+		xstrcat(out, "\n   ");
+	
+	/****** Line 2 ******/
+	if (resv_ptr->type == RESERVE_TYPE_MAINT)
+		tmp3 = "MAINT";
+	else
+		tmp3 = "";
+	snprintf(tmp_line, sizeof(tmp_line), 
+		 "Nodes=%s NodeCnt=%u Features=%s PartitionName=%s Type=%s",
+		 resv_ptr->node_list, resv_ptr->node_cnt,
+		 resv_ptr->features,  resv_ptr->partition, tmp3);
+	xstrcat(out, tmp_line);
+	if (one_liner)
+		xstrcat(out, " ");
+	else
+		xstrcat(out, "\n   ");
+	
+	/****** Line 3 ******/
+	snprintf(tmp_line, sizeof(tmp_line), 
+		 "Users=%s Accounts=%s", 
+		 resv_ptr->users, resv_ptr->accounts);
+	xstrcat(out, tmp_line);
+	if (one_liner)
+		xstrcat(out, "\n");
+	else
+		xstrcat(out, "\n\n");
+	
+	return out;
+}
+
+
+
+/*
+ * slurm_load_reservations - issue RPC to get all slurm reservation 
+ *	configuration information if changed since update_time 
+ * IN update_time - time of current configuration data
+ * IN reserve_info_msg_pptr - place to store a reservation configuration 
+ *	pointer
+ * RET 0 or a slurm error code
+ * NOTE: free the response using slurm_free_reservation_info_msg
+ */
+extern int slurm_load_reservations (time_t update_time, 
+		reserve_info_msg_t **resp)
+{
+        int rc;
+        slurm_msg_t req_msg;
+        slurm_msg_t resp_msg;
+        resv_info_request_msg_t req;
+
+	slurm_msg_t_init(&req_msg);
+	slurm_msg_t_init(&resp_msg);
+
+        req.last_update  = update_time;
+        req_msg.msg_type = REQUEST_RESERVATION_INFO;
+        req_msg.data     = &req;
+	
+	if (slurm_send_recv_controller_msg(&req_msg, &resp_msg) < 0)
+		return SLURM_ERROR;
+	
+	switch (resp_msg.msg_type) {
+	case RESPONSE_RESERVATION_INFO:
+		*resp = (reserve_info_msg_t *) resp_msg.data;
+		break;
+	case RESPONSE_SLURM_RC:
+		rc = ((return_code_msg_t *) resp_msg.data)->return_code;
+		slurm_free_return_code_msg(resp_msg.data);	
+		if (rc) 
+			slurm_seterrno_ret(rc);
+		*resp = NULL;
+		break;
+	default:
+		slurm_seterrno_ret(SLURM_UNEXPECTED_MSG_ERROR);
+		break;
+	}
+
+	return SLURM_PROTOCOL_SUCCESS;
+}
diff --git a/src/api/update_config.c b/src/api/update_config.c
index bcb54abd74d..fed93a03431 100644
--- a/src/api/update_config.c
+++ b/src/api/update_config.c
@@ -2,7 +2,8 @@
  *  update_config.c - request that slurmctld update its configuration
  *  $Id$
  *****************************************************************************
- *  Copyright (C) 2002 The Regents of the University of California.
+ *  Copyright (C) 2002-2007 The Regents of the University of California.
+ *  Copyright (C) 2008-2009 Lawrence Livermore National Security.
  *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
  *  Written by Morris Jette <jette1@llnl.gov> and Kevin Tew <tew1@llnl.gov>.
  *  LLNL-CODE-402394.
@@ -43,6 +44,7 @@
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 
 #include <slurm/slurm.h>
 
@@ -74,6 +76,17 @@ slurm_update_node ( update_node_msg_t * node_msg )
 	return _slurm_update ((void *) node_msg, REQUEST_UPDATE_NODE);
 }
 
+/*
+ * slurm_create_partition - create a new partition, only usable by user root
+ * IN part_msg - description of partition configuration
+ * RET 0 on success, otherwise return -1 and set errno to indicate the error
+ */
+int 
+slurm_create_partition ( update_part_msg_t * part_msg ) 
+{
+	return _slurm_update ((void *) part_msg, REQUEST_CREATE_PARTITION);
+}
+
 /*
  * slurm_update_partition - issue RPC to a partition's configuration per  
  *	request, only usable by user root
@@ -89,7 +102,7 @@ slurm_update_partition ( update_part_msg_t * part_msg )
 /*
  * slurm_delete_partition - issue RPC to delete a partition, only usable 
  *	by user root
- * IN part_msg - description of partition updates
+ * IN part_msg - description of partition to delete
  * RET 0 on success, otherwise return -1 and set errno to indicate the error
  */
 int 
@@ -98,6 +111,69 @@ slurm_delete_partition ( delete_part_msg_t * part_msg )
 	return _slurm_update ((void *) part_msg, REQUEST_DELETE_PARTITION);
 }
 
+/*
+ * slurm_create_reservation - create a new reservation, only usable by user root
+ * IN resv_msg - description of reservation
+ * RET name of reservation on success (caller must free the memory),
+ *	otherwise return NULL and set errno to indicate the error
+ */
+char * 
+slurm_create_reservation (reserve_request_msg_t * resv_msg ) 
+{
+	int rc;
+	char *resv_name = NULL;
+	slurm_msg_t req_msg;
+	slurm_msg_t resp_msg;
+	reservation_name_msg_t *resp;
+
+	slurm_msg_t_init(&req_msg);
+	slurm_msg_t_init(&resp_msg);
+
+	req_msg.msg_type = REQUEST_CREATE_RESERVATION;
+	req_msg.data     = resv_msg; 
+			
+	rc = slurm_send_recv_controller_msg(&req_msg, &resp_msg);
+	switch (resp_msg.msg_type) {
+	case RESPONSE_CREATE_RESERVATION:
+		resp = (reservation_name_msg_t *) resp_msg.data;
+		resv_name = strdup(resp->name);
+		break;
+	case RESPONSE_SLURM_RC:
+		rc = ((return_code_msg_t *) resp_msg.data)->return_code;
+		if (rc) 
+			slurm_seterrno(rc);
+		break;
+	default:
+		slurm_seterrno(SLURM_UNEXPECTED_MSG_ERROR);
+	}
+	slurm_free_msg_data(resp_msg.msg_type, resp_msg.data);
+	return resv_name;
+}
+
+/*
+ * slurm_update_reservation - modify an existing reservation, only usable by 
+ *	user root
+ * IN resv_msg - description of reservation
+ * RET 0 on success, otherwise return -1 and set errno to indicate the error
+ */
+extern int slurm_update_reservation ( reserve_request_msg_t * resv_msg )
+{
+	return _slurm_update ((void *) resv_msg, REQUEST_UPDATE_RESERVATION);
+}
+
+/*
+ * slurm_delete_reservation - issue RPC to delete a reservation, only usable 
+ *	by user root
+ * IN resv_msg - description of reservation to delete
+ * RET 0 on success, otherwise return -1 and set errno to indicate the error
+ */
+int 
+slurm_delete_reservation ( reservation_name_msg_t * resv_msg ) 
+{
+	return _slurm_update ((void *) resv_msg, REQUEST_DELETE_RESERVATION);
+}
+
+
 /* _slurm_update - issue RPC for all update requests */
 static int 
 _slurm_update (void *data, slurm_msg_type_t msg_type)
diff --git a/src/common/slurm_errno.c b/src/common/slurm_errno.c
index fe1f2c4f757..2dfabfe37b5 100644
--- a/src/common/slurm_errno.c
+++ b/src/common/slurm_errno.c
@@ -226,6 +226,8 @@ static slurm_errtab_t slurm_errtab[] = {
 	  "Access denied to requested reservation"		},
 	{ ESLURM_RESERVATION_INVALID,
 	  "Requested reservation is invalid"			},
+	{ ESLURM_INVALID_TIME_VALUE,
+	  "Invalid time specified"				},
 
 	/* slurmd error codes */
 
diff --git a/src/common/slurm_protocol_defs.c b/src/common/slurm_protocol_defs.c
index 32b062d4045..c4a82526928 100644
--- a/src/common/slurm_protocol_defs.c
+++ b/src/common/slurm_protocol_defs.c
@@ -4,7 +4,7 @@
  *	the slurm daemons directly, not for user client use.
  *****************************************************************************
  *  Copyright (C) 2002-2007 The Regents of the University of California.
- *  Copyright (C) 2008 Lawrence Livermore National Security.
+ *  Copyright (C) 2008-2009 Lawrence Livermore National Security.
  *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
  *  Written by Kevin Tew <tew1@llnl.gov> et. al.
  *  LLNL-CODE-402394.
@@ -67,6 +67,9 @@ static void _slurm_free_node_info_members (node_info_t * node);
 static void _free_all_partitions (partition_info_msg_t *msg);
 static void _slurm_free_partition_info_members (partition_info_t * part);
 
+static void  _free_all_reservations(reserve_info_msg_t *msg);
+static void _slurm_free_reserve_info_members (reserve_info_t * part);
+
 static void _free_all_step_info (job_step_info_response_msg_t *msg);
 static void _slurm_free_job_step_info_members (job_step_info_t * msg);
 static void _make_lower(char *change);
@@ -280,6 +283,12 @@ void inline slurm_free_part_info_request_msg(
 	xfree(msg);
 }
 
+void inline slurm_free_resv_info_request_msg(
+		resv_info_request_msg_t *msg)
+{
+	xfree(msg);
+}
+
 void slurm_free_job_desc_msg(job_desc_msg_t * msg)
 {
 	int i;
@@ -432,6 +441,27 @@ void slurm_free_delete_part_msg(delete_part_msg_t * msg)
 	}
 }
 
+void slurm_free_update_resv_msg(reserve_request_msg_t * msg)
+{
+	if (msg) {
+		xfree(msg->accounts);
+		xfree(msg->features);
+		xfree(msg->partition);
+		xfree(msg->name);
+		xfree(msg->node_list);
+		xfree(msg->users);
+		xfree(msg);
+	}
+}
+
+void slurm_free_resv_name_msg(reservation_name_msg_t * msg)
+{
+	if (msg) {
+		xfree(msg->name);
+		xfree(msg);
+	}
+}
+
 void slurm_free_job_step_create_request_msg(job_step_create_request_msg_t *
 					    msg)
 {
@@ -1295,6 +1325,49 @@ static void _slurm_free_partition_info_members(partition_info_t * part)
 	}
 }
 
+/*
+ * slurm_free_reserve_info_msg - free the reservation information 
+ *	response message
+ * IN msg - pointer to reservation information response message
+ * NOTE: buffer is loaded by slurm_load_reservation
+ */
+void slurm_free_reservation_info_msg(reserve_info_msg_t * msg)
+{
+	if (msg) {
+		if (msg->reservation_array) {
+			_free_all_reservations(msg);
+			xfree(msg->reservation_array);
+		}
+		xfree(msg);
+	}
+}
+
+static void  _free_all_reservations(reserve_info_msg_t *msg)
+{
+	int i;
+
+	if ((msg == NULL) ||
+	    (msg->reservation_array == NULL))
+		return;
+
+	for (i = 0; i < msg->record_count; i++)
+		_slurm_free_reserve_info_members(
+			&msg->reservation_array[i]);
+
+}
+
+static void _slurm_free_reserve_info_members(reserve_info_t * resv)
+{
+	if (resv) {
+		xfree(resv->accounts);
+		xfree(resv->features);
+		xfree(resv->name);
+		xfree(resv->node_list);
+		xfree(resv->partition);
+		xfree(resv->users);
+	}
+}
+
 extern void slurm_free_file_bcast_msg(file_bcast_msg_t *msg)
 {
 	if (msg) {
@@ -1438,12 +1511,21 @@ extern int slurm_free_msg_data(slurm_msg_type_t type, void *data)
 	case REQUEST_UPDATE_NODE:
 		slurm_free_update_node_msg(data);
 		break;
+	case REQUEST_CREATE_PARTITION:
 	case REQUEST_UPDATE_PARTITION:
 		slurm_free_update_part_msg(data);
 		break;
 	case REQUEST_DELETE_PARTITION:		
 		slurm_free_delete_part_msg(data);
 		break;
+	case REQUEST_CREATE_RESERVATION:
+	case REQUEST_UPDATE_RESERVATION:
+		slurm_free_update_resv_msg(data);
+		break;
+	case REQUEST_DELETE_RESERVATION:
+	case RESPONSE_CREATE_RESERVATION:		
+		slurm_free_resv_name_msg(data);
+		break;
 	case REQUEST_NODE_REGISTRATION_STATUS:
 		slurm_free_node_registration_status_msg(data);
 		break;
@@ -1535,6 +1617,7 @@ extern int slurm_free_msg_data(slurm_msg_type_t type, void *data)
 	case REQUEST_DAEMON_STATUS:
 	case REQUEST_HEALTH_CHECK:
 	case ACCOUNTING_FIRST_REG:
+	case REQUEST_RESERVATION_INFO:
 		/* No body to free */
 		break;
 	case ACCOUNTING_UPDATE_MSG:
diff --git a/src/common/slurm_protocol_defs.h b/src/common/slurm_protocol_defs.h
index 71f488ae9a0..e8a02052ab8 100644
--- a/src/common/slurm_protocol_defs.h
+++ b/src/common/slurm_protocol_defs.h
@@ -2,7 +2,7 @@
  *  slurm_protocol_defs.h - definitions used for RPCs
  *****************************************************************************
  *  Copyright (C) 2002-2007 The Regents of the University of California.
- *  Copyright (C) 2008 Lawrence Livermore National Security.
+ *  Copyright (C) 2008-2009 Lawrence Livermore National Security.
  *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
  *  Written by Kevin Tew <tew1@llnl.gov>.
  *  LLNL-CODE-402394.
@@ -119,11 +119,18 @@ typedef enum {
 	REQUEST_JOB_INFO_SINGLE,
 	REQUEST_SHARE_INFO,
 	RESPONSE_SHARE_INFO,
+	REQUEST_RESERVATION_INFO,
+	RESPONSE_RESERVATION_INFO,
 
 	REQUEST_UPDATE_JOB = 3001,
 	REQUEST_UPDATE_NODE,
-	REQUEST_UPDATE_PARTITION,
+	REQUEST_CREATE_PARTITION,
 	REQUEST_DELETE_PARTITION,
+	REQUEST_UPDATE_PARTITION,
+	REQUEST_CREATE_RESERVATION,
+	RESPONSE_CREATE_RESERVATION,
+	REQUEST_DELETE_RESERVATION,
+	REQUEST_UPDATE_RESERVATION,
 
 	REQUEST_RESOURCE_ALLOCATION = 4001,
 	RESPONSE_RESOURCE_ALLOCATION,
@@ -371,6 +378,10 @@ typedef struct part_info_request_msg {
 	uint16_t show_flags;
 } part_info_request_msg_t;
 
+typedef struct resv_info_request_msg {
+        time_t last_update;
+} resv_info_request_msg_t;
+
 typedef struct complete_job_allocation {
 	uint32_t job_id;
 	uint32_t job_rc;
@@ -795,6 +806,7 @@ void inline slurm_free_job_step_info_request_msg(
 		job_step_info_request_msg_t *msg);
 void inline slurm_free_node_info_request_msg(node_info_request_msg_t *msg);
 void inline slurm_free_part_info_request_msg(part_info_request_msg_t *msg);
+void inline slurm_free_resv_info_request_msg(resv_info_request_msg_t *msg);
 void inline slurm_free_set_debug_level_msg(set_debug_level_msg_t *msg);
 void inline slurm_destroy_association_shares_object(void *object);
 void inline slurm_free_shares_request_msg(shares_request_msg_t *msg);
@@ -825,6 +837,9 @@ void inline slurm_free_job_launch_msg(batch_job_launch_msg_t * msg);
 void inline slurm_free_update_node_msg(update_node_msg_t * msg);
 void inline slurm_free_update_part_msg(update_part_msg_t * msg);
 void inline slurm_free_delete_part_msg(delete_part_msg_t * msg);
+void inline slurm_free_update_resv_msg(reserve_request_msg_t * msg);
+void inline slurm_free_resv_name_msg(reservation_name_msg_t * msg);
+void inline slurm_free_resv_info_msg(reserve_info_msg_t * msg);
 void inline
 slurm_free_job_step_create_request_msg(job_step_create_request_msg_t * msg);
 void inline
diff --git a/src/common/slurm_protocol_pack.c b/src/common/slurm_protocol_pack.c
index 0503a91a69c..4272c92b71a 100644
--- a/src/common/slurm_protocol_pack.c
+++ b/src/common/slurm_protocol_pack.c
@@ -69,6 +69,7 @@
 #define _pack_node_select_info_msg(msg,buf)	_pack_buffer_msg(msg,buf)
 #define _pack_node_info_msg(msg,buf)		_pack_buffer_msg(msg,buf)
 #define _pack_partition_info_msg(msg,buf)	_pack_buffer_msg(msg,buf)
+#define _pack_reserve_info_msg(msg,buf)		_pack_buffer_msg(msg,buf)
 
 static void _pack_assoc_shares_object(void *in, Buf buffer);
 static int _unpack_assoc_shares_object(void **object, Buf buffer);
@@ -151,15 +152,24 @@ static int _unpack_job_step_create_response_msg(
 
 static void _pack_part_info_request_msg(part_info_request_msg_t * msg, 
 					Buf buffer);
-
 static int _unpack_part_info_request_msg(part_info_request_msg_t ** 
 					 msg, Buf buffer);
 
+static void _pack_resv_info_request_msg(resv_info_request_msg_t * msg, 
+					Buf buffer);
+static int _unpack_resv_info_request_msg(resv_info_request_msg_t ** 
+					 msg, Buf buffer);
+
 static int _unpack_partition_info_msg(partition_info_msg_t ** msg,
 				      Buf buffer);
 static int _unpack_partition_info_members(partition_info_t * part,
 					  Buf buffer);
 
+static int _unpack_reserve_info_msg(reserve_info_msg_t ** msg,
+				    Buf buffer);
+static int _unpack_reserve_info_members(reserve_info_t * resv,
+					Buf buffer);
+
 static void _pack_launch_tasks_request_msg(launch_tasks_request_msg_t *
 					   msg, Buf buffer);
 static int _unpack_launch_tasks_request_msg(launch_tasks_request_msg_t **
@@ -358,6 +368,11 @@ static void _pack_accounting_update_msg(accounting_update_msg_t *msg,
 static int _unpack_accounting_update_msg(accounting_update_msg_t **msg,
 					 Buf buffer);
 
+static void _pack_update_resv_msg(reserve_request_msg_t * msg, Buf buffer);
+static int  _unpack_update_resv_msg(reserve_request_msg_t ** msg, Buf buffer);
+static void _pack_resv_name_msg(reservation_name_msg_t * msg, Buf buffer);
+static int  _unpack_resv_name_msg(reservation_name_msg_t ** msg, Buf buffer);
+
 /* pack_header
  * packs a slurm protocol header that proceeds every slurm message
  * IN header - the header structure to pack
@@ -451,6 +466,10 @@ pack_msg(slurm_msg_t const *msg, Buf buffer)
 		_pack_part_info_request_msg((part_info_request_msg_t *)
 					    msg->data, buffer);
 		break;
+	case REQUEST_RESERVATION_INFO:
+		_pack_resv_info_request_msg((resv_info_request_msg_t *)
+					    msg->data, buffer);
+		break;
 	case REQUEST_BUILD_INFO:
 	case REQUEST_ACCTING_INFO:
 		_pack_last_update_msg((last_update_msg_t *)
@@ -523,6 +542,7 @@ pack_msg(slurm_msg_t const *msg, Buf buffer)
 		_pack_update_node_msg((update_node_msg_t *) msg->data,
 				      buffer);
 		break;
+	case REQUEST_CREATE_PARTITION:
 	case REQUEST_UPDATE_PARTITION:
 		_pack_update_partition_msg((update_part_msg_t *) msg->
 					   data, buffer);
@@ -531,6 +551,19 @@ pack_msg(slurm_msg_t const *msg, Buf buffer)
 		_pack_delete_partition_msg((delete_part_msg_t *) msg->
 					   data, buffer);
 		break;
+	case REQUEST_CREATE_RESERVATION:
+	case REQUEST_UPDATE_RESERVATION:
+		_pack_update_resv_msg((reserve_request_msg_t *) msg->
+				      data, buffer);
+		break;
+	case RESPONSE_RESERVATION_INFO:
+		_pack_reserve_info_msg((slurm_msg_t *) msg, buffer);
+		break;
+	case REQUEST_DELETE_RESERVATION:
+	case RESPONSE_CREATE_RESERVATION:
+		_pack_resv_name_msg((reservation_name_msg_t *) msg->
+				     data, buffer);
+		break;
 	case REQUEST_REATTACH_TASKS:
 		_pack_reattach_tasks_request_msg(
 			(reattach_tasks_request_msg_t *) msg->data, buffer);
@@ -787,6 +820,10 @@ unpack_msg(slurm_msg_t * msg, Buf buffer)
 		rc = _unpack_part_info_request_msg((part_info_request_msg_t **)
 						   & (msg->data), buffer);
 		break;
+	case REQUEST_RESERVATION_INFO:
+		rc = _unpack_resv_info_request_msg((resv_info_request_msg_t **)
+						   & (msg->data), buffer);
+		break;
 	case REQUEST_BUILD_INFO:
 	case REQUEST_ACCTING_INFO:
 		rc = _unpack_last_update_msg((last_update_msg_t **) &
@@ -864,6 +901,7 @@ unpack_msg(slurm_msg_t * msg, Buf buffer)
 		rc = _unpack_update_node_msg((update_node_msg_t **) &
 					     (msg->data), buffer);
 		break;
+	case REQUEST_CREATE_PARTITION:
 	case REQUEST_UPDATE_PARTITION:
 		rc = _unpack_update_partition_msg((update_part_msg_t **) &
 						  (msg->data), buffer);
@@ -872,6 +910,20 @@ unpack_msg(slurm_msg_t * msg, Buf buffer)
 		rc = _unpack_delete_partition_msg((delete_part_msg_t **) &
 						  (msg->data), buffer);
 		break;
+	case REQUEST_CREATE_RESERVATION:
+	case REQUEST_UPDATE_RESERVATION:
+		rc = _unpack_update_resv_msg((reserve_request_msg_t **)
+					     &(msg->data), buffer);
+		break;
+	case REQUEST_DELETE_RESERVATION:
+	case RESPONSE_CREATE_RESERVATION:
+		rc = _unpack_resv_name_msg((reservation_name_msg_t **)
+					     &(msg->data), buffer);
+		break;
+	case RESPONSE_RESERVATION_INFO:
+		rc = _unpack_reserve_info_msg((reserve_info_msg_t **)
+					     &(msg->data), buffer);
+		break;
 	case REQUEST_LAUNCH_TASKS:
 		rc = _unpack_launch_tasks_request_msg(
 			(launch_tasks_request_msg_t **)
@@ -1746,6 +1798,57 @@ unpack_error:
 	return SLURM_ERROR;
 }
 
+static void
+_pack_update_resv_msg(reserve_request_msg_t * msg, Buf buffer)
+{
+	xassert(msg != NULL);
+
+	packstr(msg->name,         buffer);
+	pack_time(msg->start_time, buffer);
+	pack_time(msg->end_time,   buffer);
+	pack32(msg->duration,      buffer);
+	pack16(msg->type,          buffer);
+	pack32(msg->node_cnt,      buffer);
+	packstr(msg->node_list,    buffer);
+	packstr(msg->features,     buffer);
+	packstr(msg->partition,    buffer);
+
+	packstr(msg->users,        buffer);
+	packstr(msg->accounts,     buffer);
+}
+
+static int
+_unpack_update_resv_msg(reserve_request_msg_t ** msg, Buf buffer)
+{
+	uint32_t uint32_tmp;
+	reserve_request_msg_t *tmp_ptr;
+
+	xassert(msg != NULL);
+
+	/* alloc memory for structure */
+	tmp_ptr = xmalloc(sizeof(reserve_request_msg_t));
+	*msg = tmp_ptr;
+
+	safe_unpackstr_xmalloc(&tmp_ptr->name, &uint32_tmp, buffer);
+	safe_unpack_time(&tmp_ptr->start_time, buffer);
+	safe_unpack_time(&tmp_ptr->end_time,   buffer);
+	safe_unpack32(&tmp_ptr->duration,      buffer);
+	safe_unpack16(&tmp_ptr->type,          buffer);
+	safe_unpack32(&tmp_ptr->node_cnt,      buffer);
+	safe_unpackstr_xmalloc(&tmp_ptr->node_list, &uint32_tmp, buffer);
+	safe_unpackstr_xmalloc(&tmp_ptr->features,  &uint32_tmp, buffer);
+	safe_unpackstr_xmalloc(&tmp_ptr->partition, &uint32_tmp, buffer);
+
+	safe_unpackstr_xmalloc(&tmp_ptr->users,     &uint32_tmp, buffer);	
+	safe_unpackstr_xmalloc(&tmp_ptr->accounts,  &uint32_tmp, buffer);
+	return SLURM_SUCCESS;
+
+unpack_error:
+	slurm_free_update_resv_msg(tmp_ptr);
+	*msg = NULL;
+	return SLURM_ERROR;
+}
+
 static void
 _pack_delete_partition_msg(delete_part_msg_t * msg, Buf buffer)
 {
@@ -1775,6 +1878,35 @@ unpack_error:
 	return SLURM_ERROR;
 }
 
+static void
+_pack_resv_name_msg(reservation_name_msg_t * msg, Buf buffer)
+{
+	xassert(msg != NULL);
+
+	packstr(msg->name,         buffer);
+}
+
+static int
+_unpack_resv_name_msg(reservation_name_msg_t ** msg, Buf buffer)
+{
+	uint32_t uint32_tmp;
+	reservation_name_msg_t *tmp_ptr;
+
+	xassert(msg != NULL);
+
+	/* alloc memory for structure */
+	tmp_ptr = xmalloc(sizeof(reservation_name_msg_t));
+	*msg = tmp_ptr;
+
+	safe_unpackstr_xmalloc(&tmp_ptr->name, &uint32_tmp, buffer);
+	return SLURM_SUCCESS;
+
+unpack_error:
+	slurm_free_resv_name_msg(tmp_ptr);
+	*msg = NULL;
+	return SLURM_ERROR;
+}
+
 static void
 _pack_job_step_create_request_msg(job_step_create_request_msg_t
 				  * msg, Buf buffer)
@@ -2050,7 +2182,7 @@ _unpack_partition_info_msg(partition_info_msg_t ** msg, Buf buffer)
 	partition = (*msg)->partition_array =
 		xmalloc(sizeof(partition_info_t) * (*msg)->record_count);
 
-	/* load individual job info */
+	/* load individual partition info */
 	for (i = 0; i < (*msg)->record_count; i++) {
 		if (_unpack_partition_info_members(&partition[i], buffer))
 			goto unpack_error;
@@ -2108,48 +2240,62 @@ unpack_error:
 	return SLURM_ERROR;
 }
 
-/* pack_job_step_info_members
- * pack selected fields of the description of a job into a buffer
- * IN job_id, step_id, user_id, start_time, partition, nodes - job info
- * IN/OUT buffer - destination of the pack, contains pointers that are 
- *			automatically updated
- */
-/* void */
-/* pack_job_step_info_members(uint32_t job_id, uint16_t step_id, */
-/* 			   uint32_t user_id, uint32_t num_tasks, */
-/* 			   time_t start_time, char *partition,  */
-/* 			   char *nodes, char *name, char *network, */
-/* 			   Buf buffer) */
-/* { */
-/* 	pack32((uint32_t)job_id, buffer); */
-/* 	pack16((uint16_t)step_id, buffer); */
-/* 	pack32((uint32_t)user_id, buffer); */
-/* 	pack32((uint32_t)num_tasks, buffer); */
-
-/* 	pack_time(start_time, buffer); */
-/* 	packstr(partition, buffer); */
-/* 	packstr(nodes, buffer); */
-/* 	packstr(name, buffer); */
-/* 	packstr(network, buffer); */
-/* } */
-
-/* pack_job_step_info
- * packs a slurm job steps info
- * IN step - pointer to the job step info
- * IN/OUT buffer - destination of the pack, contains pointers that are 
- *			automatically updated
- */
-/* void */
-/* pack_job_step_info(job_step_info_t * step, Buf buffer) */
-/* { */
-/* 	pack_job_step_info_members(step->job_id, */
-/* 				   step->step_id, */
-/* 				   step->user_id, */
-/* 				   step->num_tasks, */
-/* 				   step->start_time, */
-/* 				   step->partition, step->nodes,  */
-/* 				   step->name, step->network, buffer); */
-/* } */
+static int
+_unpack_reserve_info_msg(reserve_info_msg_t ** msg, Buf buffer)
+{
+	int i;
+	reserve_info_t *reserve = NULL;
+
+	xassert(msg != NULL);
+	*msg = xmalloc(sizeof(reserve_info_msg_t));
+
+	/* load buffer's header (data structure version and time) */
+	safe_unpack32(&((*msg)->record_count), buffer);
+	safe_unpack_time(&((*msg)->last_update), buffer);
+
+	reserve = (*msg)->reservation_array =
+		xmalloc(sizeof(reserve_info_t) * (*msg)->record_count);
+
+	/* load individual reservation records */
+	for (i = 0; i < (*msg)->record_count; i++) {
+		if (_unpack_reserve_info_members(&reserve[i], buffer))
+			goto unpack_error;
+	}
+	return SLURM_SUCCESS;
+
+unpack_error:
+	slurm_free_reservation_info_msg(*msg);
+	*msg = NULL;
+	return SLURM_ERROR;
+}
+
+
+static int
+_unpack_reserve_info_members(reserve_info_t * resv, Buf buffer)
+{
+	uint32_t uint32_tmp;
+
+	safe_unpackstr_xmalloc(&resv->accounts,	&uint32_tmp, buffer);
+	safe_unpack_time(&resv->end_time,	buffer);
+	safe_unpackstr_xmalloc(&resv->features,	&uint32_tmp, buffer);
+	safe_unpackstr_xmalloc(&resv->name,	&uint32_tmp, buffer);
+	safe_unpack32(&resv->node_cnt,		buffer);
+	safe_unpackstr_xmalloc(&resv->node_list,&uint32_tmp, buffer);
+	safe_unpackstr_xmalloc(&resv->partition,&uint32_tmp, buffer);
+	safe_unpack_time(&resv->start_time,	buffer);
+	safe_unpack16(&resv->type,		buffer);
+	safe_unpackstr_xmalloc(&resv->users,	&uint32_tmp, buffer);
+	return SLURM_SUCCESS;
+
+unpack_error:
+	xfree(resv->accounts);
+	xfree(resv->features);
+	xfree(resv->name);
+	xfree(resv->node_list);
+	xfree(resv->partition);
+	xfree(resv->users);
+	return SLURM_ERROR;
+}
 
 /* _unpack_job_step_info_members
  * unpacks a set of slurm job step info for one job step
@@ -3853,6 +3999,29 @@ unpack_error:
 	return SLURM_ERROR;
 }
 
+static void
+_pack_resv_info_request_msg(resv_info_request_msg_t * msg, Buf buffer)
+{
+	pack_time(msg->last_update, buffer);
+}
+
+static int
+_unpack_resv_info_request_msg(resv_info_request_msg_t ** msg, Buf buffer)
+{
+	resv_info_request_msg_t* resv_info;
+
+	resv_info = xmalloc(sizeof(resv_info_request_msg_t));
+	*msg = resv_info;
+
+	safe_unpack_time(&resv_info->last_update, buffer);
+	return SLURM_SUCCESS;
+
+unpack_error:
+	slurm_free_resv_info_request_msg(resv_info);
+	*msg = NULL;
+	return SLURM_ERROR;
+}
+
 static void
 _pack_slurm_addr_array(slurm_addr * slurm_address,
 		       uint32_t size_val, Buf buffer)
diff --git a/src/scontrol/Makefile.am b/src/scontrol/Makefile.am
index b0ec55397ce..7e5907dbb0e 100644
--- a/src/scontrol/Makefile.am
+++ b/src/scontrol/Makefile.am
@@ -7,9 +7,11 @@ INCLUDES = -I$(top_srcdir)
 bin_PROGRAMS = scontrol
 
 scontrol_SOURCES =	\
+	create_res.c	\
 	info_job.c	\
 	info_node.c	\
 	info_part.c	\
+	info_res.c	\
 	scontrol.c	\
 	scontrol.h	\
 	update_job.c	\
diff --git a/src/scontrol/Makefile.in b/src/scontrol/Makefile.in
index d5faafec505..c96a4b78f40 100644
--- a/src/scontrol/Makefile.in
+++ b/src/scontrol/Makefile.in
@@ -74,8 +74,8 @@ CONFIG_CLEAN_FILES =
 am__installdirs = "$(DESTDIR)$(bindir)"
 binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
 PROGRAMS = $(bin_PROGRAMS)
-am_scontrol_OBJECTS = info_job.$(OBJEXT) info_node.$(OBJEXT) \
-	info_part.$(OBJEXT) scontrol.$(OBJEXT) update_job.$(OBJEXT) \
+am_scontrol_OBJECTS = create_res.$(OBJEXT) info_job.$(OBJEXT) info_node.$(OBJEXT) \
+	info_part.$(OBJEXT) info_res.$(OBJEXT) scontrol.$(OBJEXT) update_job.$(OBJEXT) \
 	update_node.$(OBJEXT) update_part.$(OBJEXT)
 scontrol_OBJECTS = $(am_scontrol_OBJECTS)
 am__DEPENDENCIES_1 = $(top_builddir)/src/api/libslurm.o
@@ -273,9 +273,11 @@ top_srcdir = @top_srcdir@
 AUTOMAKE_OPTIONS = foreign
 INCLUDES = -I$(top_srcdir)
 scontrol_SOURCES = \
+	create_res.c	\
 	info_job.c	\
 	info_node.c	\
 	info_part.c	\
+	info_res.c	\
 	scontrol.c	\
 	scontrol.h	\
 	update_job.c	\
@@ -359,9 +361,11 @@ mostlyclean-compile:
 distclean-compile:
 	-rm -f *.tab.c
 
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/create_res.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/info_job.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/info_node.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/info_part.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/info_res.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/scontrol.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/update_job.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/update_node.Po@am__quote@
diff --git a/src/scontrol/create_res.c b/src/scontrol/create_res.c
new file mode 100644
index 00000000000..bd22f958f57
--- /dev/null
+++ b/src/scontrol/create_res.c
@@ -0,0 +1,310 @@
+/*****************************************************************************\
+ *  create_res.c - reservation creation function for scontrol.
+ *****************************************************************************
+ *  Copyright (C) 2009 Lawrence Livermore National Security.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by David Bremer <dbremer@llnl.gov>
+ *  LLNL-CODE-402394.
+ *  
+ *  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.
+ *
+ *  In addition, as a special exception, the copyright holders give permission 
+ *  to link the code of portions of this program with the OpenSSL library under
+ *  certain conditions as described in each individual source file, and 
+ *  distribute linked combinations including the two. You must obey the GNU 
+ *  General Public License in all respects for all of the code used other than 
+ *  OpenSSL. If you modify file(s) with this exception, you may extend this 
+ *  exception to your version of the file(s), but you are not obligated to do 
+ *  so. If you do not wish to do so, delete this exception statement from your
+ *  version.  If you delete this exception statement from all source files in 
+ *  the program, then also delete it here.
+ *  
+ *  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.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA.
+\*****************************************************************************/
+
+#include "src/scontrol/scontrol.h"
+#include "src/slurmctld/reservation.h"
+
+
+/*
+ *  process_plus_minus is used to convert a string like
+ *       Users+=a,b,c
+ *  to   Users=+a,+b,+c
+ */
+
+static char *
+process_plus_minus(char plus_or_minus, char *src)
+{
+	int num_commas = 0;
+	int ii;
+	int srclen = strlen(src);
+	char *dst, *ret;
+
+	for (ii=0; ii<srclen; ii++) {
+		if (src[ii] == ',')
+			num_commas++;
+	}
+	ret = dst = malloc(srclen + 2 + num_commas);
+
+	*dst++ = plus_or_minus;
+	for (ii=0; ii<srclen; ii++) {
+		if (*src == ',') {
+			*dst++ = *src++;
+			*dst++ = plus_or_minus;
+		} else {
+			*dst++ = *src++;
+		}
+	}
+	*dst = '\0';
+
+	return ret;
+}
+
+
+
+/* 
+ * scontrol_parse_res_options   parse options for creating or updating a 
+                                reservation
+ * IN argc - count of arguments
+ * IN argv - list of arguments
+ * IN msg  - a string to append to any error message
+ * OUT resv_msg_ptr - struct holding reservation parameters
+ * OUT free_user_str - bool indicating that resv_msg_ptr->users should be freed 
+ * OUT free_acct_str - bool indicating that resv_msg_ptr->accounts should be freed 
+ * RET 0 on success, -1 on err and prints message
+ */
+extern int
+scontrol_parse_res_options(int argc, char *argv[], const char *msg, 
+			   reserve_request_msg_t  *resv_msg_ptr, 
+			   int *free_user_str, int *free_acct_str)
+{
+	int i;
+	int duration = -3;   /* -1 == INFINITE, -2 == error, -3 == not set */
+
+	*free_user_str = 0;
+	*free_acct_str = 0;
+
+	for (i=0; i<argc; i++) {
+		if        (strncasecmp(argv[i], "ReservationName=", 16) == 0) {
+			resv_msg_ptr->name = &argv[i][16];
+
+		} else if (strncasecmp(argv[i], "StartTime=", 10) == 0) {
+			time_t  t = parse_time(&argv[i][10], 0);
+			if (t == 0) {
+				//TODO:  Set errno here instead of exit_code?
+				exit_code = 1;
+				error("Invalid start time %s.  %s", argv[i], msg);
+				return -1;
+			}
+			resv_msg_ptr->start_time = t;
+
+		} else if (strncasecmp(argv[i], "EndTime=", 8) == 0) {
+			time_t  t = parse_time(&argv[i][8], 0);
+			if (t == 0) {
+				//TODO:  Set errno here instead of exit_code?
+				exit_code = 1;
+				error("Invalid end time %s.  %s", argv[i], msg);
+				return -1;
+			}
+			resv_msg_ptr->end_time = t;
+
+		} else if (strncasecmp(argv[i], "Duration=", 9) == 0) {
+			/* -1 == INFINITE, -2 == error, -3 == not set */
+			duration = time_str2mins(&argv[i][9]);
+			if (duration < 0 && duration != INFINITE) {
+				//TODO:  Set errno here instead of exit_code?
+				exit_code = 1;
+				error("Invalid duration %s.  %s", argv[i], msg);
+				return -1;
+			}
+			resv_msg_ptr->duration = (uint32_t)duration;
+
+		} else if (strncasecmp(argv[i], "Type=", 5) == 0) {
+			char *typestr = &argv[i][5];
+			if (strncasecmp(typestr, "Maintenance", 5) == 0) {
+				resv_msg_ptr->type = RESERVE_TYPE_MAINT;
+			} else {
+				exit_code = 1;
+				error("Invalid type %s.  %s", argv[i], msg);
+				return -1;
+			}
+		} else if (strncasecmp(argv[i], "NodeCnt=", 8) == 0) {
+			char *endptr = NULL;
+			resv_msg_ptr->node_cnt = strtol(&argv[i][8], &endptr, 10);
+
+			if (endptr == NULL || *endptr != '\0' || 
+                            argv[i][8] == '\0') {
+				exit_code = 1;
+				error("Invalid node count %s.  %s", argv[i], msg);
+				return -1;
+			}
+		} else if (strncasecmp(argv[i], "Nodes=", 6) == 0) {
+			resv_msg_ptr->node_list = &argv[i][6];
+		} else if (strncasecmp(argv[i], "Features=", 9) == 0) {
+			resv_msg_ptr->features = &argv[i][9];
+		} else if (strncasecmp(argv[i], "PartitionName=", 14) == 0) {
+			resv_msg_ptr->partition = &argv[i][14];
+		} else if (strncasecmp(argv[i], "Users=", 6) == 0) {
+			resv_msg_ptr->users = &argv[i][6];
+		} else if (strncasecmp(argv[i], "Users+=", 7) == 0) {
+			resv_msg_ptr->users = process_plus_minus('+', &argv[i][7]);
+			*free_user_str = 1;
+		} else if (strncasecmp(argv[i], "Users-=", 7) == 0) {
+			resv_msg_ptr->users = process_plus_minus('-', &argv[i][7]);
+			*free_user_str = 1;
+		} else if (strncasecmp(argv[i], "Accounts=", 9) == 0) {
+			resv_msg_ptr->accounts = &argv[i][9];
+		} else if (strncasecmp(argv[i], "Accounts+=", 10) == 0) {
+			resv_msg_ptr->accounts = process_plus_minus('+', &argv[i][10]);
+			*free_acct_str = 1;
+		} else if (strncasecmp(argv[i], "Accounts-=", 10) == 0) {
+			resv_msg_ptr->accounts = process_plus_minus('-', &argv[i][10]);
+			*free_acct_str = 1;
+		} else if (strncasecmp(argv[i], "res", 3) == 0) {
+			continue;
+		} else {
+			exit_code = 1;
+			error("Unknown parameter %s.  %s", argv[i], msg);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+
+
+/* 
+ * scontrol_update_res - update the slurm reservation configuration per the 
+ *     supplied arguments 
+ * IN argc - count of arguments
+ * IN argv - list of arguments
+ * RET 0 if no slurm error, errno otherwise. parsing error prints 
+ *     error message and returns 0.
+ */
+extern int
+scontrol_update_res(int argc, char *argv[])
+{
+	reserve_request_msg_t   resv_msg;
+	int err, ret = 0;
+	int free_user_str = 0, free_acct_str = 0;
+
+	slurm_init_resv_desc_msg (&resv_msg);
+	err = scontrol_parse_res_options(argc, argv, "No reservation update.",
+					 &resv_msg, &free_user_str, &free_acct_str);
+	if (err)
+		goto SCONTROL_UPDATE_RES_CLEANUP;
+
+	if (resv_msg.name == NULL) {
+		exit_code = 1;
+		error("ReservationName must be given.  No reservation update.");
+		goto SCONTROL_UPDATE_RES_CLEANUP;
+	}
+
+	err = slurm_update_reservation(&resv_msg);
+	if (err) {
+		exit_code = 1;
+		slurm_perror("Error updating the reservation.");
+		ret = slurm_get_errno();
+	} else {
+		printf("Reservation updated.\n");
+	}
+
+SCONTROL_UPDATE_RES_CLEANUP:
+	if (free_user_str)  free(resv_msg.users);
+	if (free_acct_str)  free(resv_msg.accounts);
+	return ret;
+}
+
+
+
+/* 
+ * scontrol_create_res - create the slurm reservation configuration per the 
+ *     supplied arguments 
+ * IN argc - count of arguments
+ * IN argv - list of arguments
+ * RET 0 if no slurm error, errno otherwise. parsing error prints 
+ *     error message and returns 0.
+ */
+extern int
+scontrol_create_res(int argc, char *argv[])
+{
+	reserve_request_msg_t   resv_msg;
+	char *new_res_name = NULL;
+	int free_user_str = 0, free_acct_str = 0;
+	int err, ret = 0;
+
+	slurm_init_resv_desc_msg (&resv_msg);
+	err = scontrol_parse_res_options(argc, argv, "No reservation created.", 
+					 &resv_msg, &free_user_str, &free_acct_str);
+	if (err)
+		goto SCONTROL_CREATE_RES_CLEANUP;
+
+	if (resv_msg.start_time == (time_t)NO_VAL) {
+		exit_code = 1;
+		error("A start time must be given.  No reservation created.");
+		goto SCONTROL_CREATE_RES_CLEANUP;
+	}
+	if (resv_msg.end_time == (time_t)NO_VAL && 
+	    resv_msg.duration == (uint32_t)NO_VAL) {
+		exit_code = 1;
+		error("An end time or duration must be given.  "
+		      "No reservation created.");
+		goto SCONTROL_CREATE_RES_CLEANUP;
+	}
+	if (resv_msg.end_time != (time_t)NO_VAL && 
+	    resv_msg.duration != (uint32_t)NO_VAL && 
+            resv_msg.start_time + resv_msg.duration*60 != resv_msg.end_time) {
+		exit_code = 1;
+		error("StartTime + Duration does not equal EndTime.  "
+		      "No reservation created.");
+		goto SCONTROL_CREATE_RES_CLEANUP;
+	}
+	if (resv_msg.start_time > resv_msg.end_time && 
+	    resv_msg.end_time != (time_t)NO_VAL) {
+		exit_code = 1;
+		error("Start time cannot be after end time.  "
+		      "No reservation created.");
+		goto SCONTROL_CREATE_RES_CLEANUP;
+	}
+	if (resv_msg.node_cnt == NO_VAL && resv_msg.node_list == NULL) {
+		exit_code = 1;
+		error("Either Nodes or NodeCnt must be specified.  "
+		      "No reservation created.");
+		goto SCONTROL_CREATE_RES_CLEANUP;
+	}
+	if (resv_msg.users == NULL && resv_msg.accounts == NULL) {
+		exit_code = 1;
+		error("Either Users or Accounts must be specified.  "
+		      "No reservation created.");
+		goto SCONTROL_CREATE_RES_CLEANUP;
+	}
+
+	new_res_name = slurm_create_reservation(&resv_msg);
+	if (!new_res_name) {
+		exit_code = 1;
+		slurm_perror("Error creating the reservation");
+		ret = slurm_get_errno();
+	} else {
+		printf("Reservation created: %s\n", new_res_name);
+		free(new_res_name);
+	}
+SCONTROL_CREATE_RES_CLEANUP:
+	if (free_user_str)  
+		free(resv_msg.users);
+	if (free_acct_str)  
+		free(resv_msg.accounts);
+	return ret;
+}
diff --git a/src/scontrol/info_part.c b/src/scontrol/info_part.c
index 8c9e0606968..9d5a64abd25 100644
--- a/src/scontrol/info_part.c
+++ b/src/scontrol/info_part.c
@@ -79,7 +79,7 @@ scontrol_load_partitions (partition_info_msg_t **part_buffer_pptr)
 }
 
 /*
- * scontrol_print_par - print the specified partition's information
+ * scontrol_print_part - print the specified partition's information
  * IN partition_name - NULL to print information about all partition 
  */
 extern void 
diff --git a/src/scontrol/info_res.c b/src/scontrol/info_res.c
new file mode 100644
index 00000000000..db74df81f86
--- /dev/null
+++ b/src/scontrol/info_res.c
@@ -0,0 +1,139 @@
+/*****************************************************************************\
+ *  info_res.c - reservation information functions for scontrol.
+ *****************************************************************************
+ *  Copyright (C) 2009 Lawrence Livermore National Security.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by David Bremer <dbremer@llnl.gov>
+ *  LLNL-CODE-402394.
+ *  
+ *  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.
+ *
+ *  In addition, as a special exception, the copyright holders give permission 
+ *  to link the code of portions of this program with the OpenSSL library under
+ *  certain conditions as described in each individual source file, and 
+ *  distribute linked combinations including the two. You must obey the GNU 
+ *  General Public License in all respects for all of the code used other than 
+ *  OpenSSL. If you modify file(s) with this exception, you may extend this 
+ *  exception to your version of the file(s), but you are not obligated to do 
+ *  so. If you do not wish to do so, delete this exception statement from your
+ *  version.  If you delete this exception statement from all source files in 
+ *  the program, then also delete it here.
+ *  
+ *  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.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA.
+\*****************************************************************************/
+
+#include "scontrol.h"
+
+/* Load current reservation table information into *res_buffer_pptr */
+extern int 
+scontrol_load_reservations(reserve_info_msg_t **res_buffer_pptr)
+{
+	int error_code;
+	static reserve_info_msg_t *old_res_info_ptr = NULL;
+	reserve_info_msg_t *res_info_ptr = NULL;
+
+	if (old_res_info_ptr) {
+		error_code = slurm_load_reservations (
+						old_res_info_ptr->last_update,
+						&res_info_ptr);
+		if (error_code == SLURM_SUCCESS) {
+			slurm_free_reservation_info_msg (old_res_info_ptr);
+
+		} else if (slurm_get_errno () == SLURM_NO_CHANGE_IN_DATA) {
+			res_info_ptr = old_res_info_ptr;
+			error_code = SLURM_SUCCESS;
+			if (quiet_flag == -1)
+				printf ("slurm_load_reservations: no change in data\n");
+		}
+	}
+	else
+		error_code = slurm_load_reservations((time_t) NULL,
+						     &res_info_ptr);
+
+	if (error_code == SLURM_SUCCESS) {
+		old_res_info_ptr = res_info_ptr;
+		*res_buffer_pptr = res_info_ptr;
+	}
+
+	return error_code;
+}
+
+/*
+ * scontrol_print_res - print the specified reservation's information
+ * IN reservation_name - NULL to print information about all reservations
+ */
+extern void 
+scontrol_print_res (char *reservation_name) 
+{
+	int error_code, i, print_cnt = 0;
+	reserve_info_msg_t *res_info_ptr = NULL;
+	reserve_info_t *res_ptr = NULL;
+
+	error_code = scontrol_load_reservations(&res_info_ptr);
+	if (error_code) {
+		exit_code = 1;
+		if (quiet_flag != 1)
+			slurm_perror ("slurm_load_reservations error");
+		return;
+	}
+
+	if (quiet_flag == -1) {
+		char time_str[32];
+		slurm_make_time_str ((time_t *)&res_info_ptr->last_update, 
+			       time_str, sizeof(time_str));
+		printf ("last_update_time=%s, records=%d\n", 
+			time_str, res_info_ptr->record_count);
+	}
+
+	res_ptr = res_info_ptr->reservation_array;
+	for (i = 0; i < res_info_ptr->record_count; i++) {
+		if (reservation_name && 
+		    strcmp (reservation_name, res_ptr[i].name) != 0)
+			continue;
+		print_cnt++;
+		slurm_print_reservation_info (stdout, & res_ptr[i], 
+		                              one_liner ) ;
+		if (reservation_name)
+			break;
+	}
+
+	if (print_cnt == 0) {
+		if (reservation_name) {
+			exit_code = 1;
+			if (quiet_flag != 1)
+				printf ("Reservation %s not found\n", 
+				        reservation_name);
+		} else if (quiet_flag != 1)
+			printf ("No reservations in the system\n");
+	}
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/scontrol/scontrol.c b/src/scontrol/scontrol.c
index 8118836f10d..9a2c3186ec0 100644
--- a/src/scontrol/scontrol.c
+++ b/src/scontrol/scontrol.c
@@ -51,6 +51,7 @@ int one_liner;		/* one record per line if =1 */
 int quiet_flag;		/* quiet=1, verbose=-1, normal=0 */
 int verbosity;		/* count of "-v" options */
 
+static void	_create_it (int argc, char *argv[]);
 static void	_delete_it (int argc, char *argv[]);
 static int	_get_command (int *argc, char *argv[]);
 static void     _ping_slurmctld(char *control_machine, char *backup_controller);
@@ -489,6 +490,15 @@ _process_command (int argc, char *argv[])
 		}
 		scontrol_print_completing();
 	}
+	else if (strncasecmp (argv[0], "create", 1) == 0) {
+		if (argc < 2) {
+			exit_code = 1;
+			fprintf (stderr, "too few arguments for %s keyword\n",
+				 argv[0]);
+			return 0;
+		}		
+		_create_it ((argc - 1), &argv[1]);
+	}
 	else if (strncasecmp (argv[0], "exit", 1) == 0) {
 		if (argc > 1) {
 			exit_code = 1;
@@ -751,6 +761,12 @@ _process_command (int argc, char *argv[])
 			else
 				scontrol_print_part (NULL);
 		}
+		else if (strncasecmp (argv[1], "reservations", 3) == 0) {
+			if (argc > 2)
+				scontrol_print_res(argv[2]);
+			else
+				scontrol_print_res(NULL);
+		}
 		else if (strncasecmp (argv[1], "slurmd", 6) == 0) {
 			if (argc > 2)
 				_print_slurmd(argv[2]);
@@ -867,6 +883,35 @@ _process_command (int argc, char *argv[])
 	return 0;
 }
 
+
+/* 
+ * _create_it - create a slurm configuration per the supplied arguments 
+ * IN argc - count of arguments
+ * IN argv - list of arguments
+ */
+static void
+_create_it (int argc, char *argv[]) 
+{
+	int i;
+	for (i=0; i<argc; i++) {
+		if (strncasecmp (argv[i], "res", 3) == 0) {
+			scontrol_create_res(argc, argv);
+			break;
+		} else if (strncasecmp (argv[i], "par", 3) == 0) {
+			scontrol_create_part(argc, argv);
+			break;
+		}
+	}
+
+	if (i >= argc) {
+		exit_code = 1;
+		error("Invalid creation entity: %s\n", argv[0]);
+	}
+}
+
+
+
+
 /* 
  * _delete_it - delete the slurm the specified slurm entity 
  * IN argc - count of arguments
@@ -875,16 +920,23 @@ _process_command (int argc, char *argv[])
 static void
 _delete_it (int argc, char *argv[]) 
 {
-	delete_part_msg_t part_msg;
-
 	/* First identify the entity type to delete */
 	if (strncasecmp (argv[0], "PartitionName=", 14) == 0) {
+		delete_part_msg_t part_msg;
 		part_msg.name = argv[0] + 14;
 		if (slurm_delete_partition(&part_msg)) {
 			char errmsg[64];
 			snprintf(errmsg, 64, "delete_partition %s", argv[0]);
 			slurm_perror(errmsg);
 		}
+	} else if (strncasecmp (argv[0], "ReservationName=", 16) == 0) {
+		reservation_name_msg_t   res_msg;
+		res_msg.name = argv[0] + 16;
+		if (slurm_delete_reservation(&res_msg)) {
+			char errmsg[64];
+			snprintf(errmsg, 64, "delete_reservation %s", argv[0]);
+			slurm_perror(errmsg);
+		}
 	} else {
 		exit_code = 1;
 		fprintf(stderr, "Invalid deletion entity: %s\n", argv[1]);
@@ -919,6 +971,9 @@ _update_it (int argc, char *argv[])
 		} else if (strncasecmp (argv[i], "SubBPName=", 10) == 0) {
 			error_code = _update_bluegene_subbp (argc, argv);
 			break;
+		} else if (strncasecmp (argv[i], "ReservationName=", 16) == 0) {
+			error_code = scontrol_update_res (argc, argv);
+			break;
 		}
 		
 	}
diff --git a/src/scontrol/scontrol.h b/src/scontrol/scontrol.h
index 3fd1d289736..b19588ed4d0 100644
--- a/src/scontrol/scontrol.h
+++ b/src/scontrol/scontrol.h
@@ -115,13 +115,17 @@ extern void	scontrol_print_node (char *node_name,
 			node_info_msg_t *node_info_ptr);
 extern void	scontrol_print_node_list (char *node_list);
 extern void	scontrol_print_part (char *partition_name);
+extern void	scontrol_print_res (char *reservation_name);
 extern void	scontrol_print_step (char *job_step_id_str);
 extern int	scontrol_requeue(char *job_step_id_str);
 extern int	scontrol_suspend(char *op, char *job_id_str);
 extern int	scontrol_update_job (int argc, char *argv[]);
 extern int	scontrol_update_node (int argc, char *argv[]);
 extern int	scontrol_update_part (int argc, char *argv[]);
+extern int	scontrol_update_res (int argc, char *argv[]);
 extern void     scontrol_list_pids(const char *jobid_str,
 				   const char *node_name);
+extern int	scontrol_create_part(int argc, char *argv[]);
+extern int	scontrol_create_res(int argc, char *argv[]);
 
 #endif
diff --git a/src/scontrol/update_part.c b/src/scontrol/update_part.c
index 6ec952c928b..38e77a56e38 100644
--- a/src/scontrol/update_part.c
+++ b/src/scontrol/update_part.c
@@ -38,155 +38,181 @@
 #include "src/common/proc_args.h"
 #include "src/scontrol/scontrol.h"
 
-
-/* 
- * scontrol_update_part - update the slurm partition configuration per the 
- *	supplied arguments 
- * IN argc - count of arguments
- * IN argv - list of arguments
- * RET 0 if no slurm error, errno otherwise. parsing error prints 
- *			error message and returns 0
- */
 extern int
-scontrol_update_part (int argc, char *argv[]) 
+scontrol_parse_part_options (int argc, char *argv[], int *update_cnt_ptr, 
+			     update_part_msg_t *part_msg_ptr) 
 {
-	int i, min, max, update_cnt = 0;
-	update_part_msg_t part_msg;
+	int i, min, max;
+	if (!update_cnt_ptr) {
+		error("scontrol_parse_part_options internal error, "
+		      "update_cnt_ptr == NULL");
+		exit_code = 1;
+		return -1; 
+	}
+	if (!part_msg_ptr) {
+		error("scontrol_parse_part_options internal error, "
+		      "part_msg_ptr == NULL");
+		exit_code = 1;
+		return -1; 
+	}
 
-	slurm_init_part_desc_msg ( &part_msg );
 	for (i=0; i<argc; i++) {
 		if (strncasecmp(argv[i], "PartitionName=", 14) == 0)
-			part_msg.name = &argv[i][14];
+			part_msg_ptr->name = &argv[i][14];
 		else if (strncasecmp(argv[i], "MaxTime=", 8) == 0) {
 			int max_time = time_str2mins(&argv[i][8]);
 			if ((max_time < 0) && (max_time != INFINITE)) {
 				exit_code = 1;
 				error("Invalid input %s", argv[i]);
-				return 0;
+				return -1;
 			}
-			part_msg.max_time = max_time;
-			update_cnt++;
+			part_msg_ptr->max_time = max_time;
+			(*update_cnt_ptr)++;
 		}
 		else if (strncasecmp(argv[i], "MaxNodes=", 9) == 0) {
 			if ((strcasecmp(&argv[i][9],"UNLIMITED") == 0) ||
 			    (strcasecmp(&argv[i][8],"INFINITE") == 0))
-				part_msg.max_nodes = (uint32_t) INFINITE;
+				part_msg_ptr->max_nodes = (uint32_t) INFINITE;
 			else {
 				min = 1;
 				get_resource_arg_range(&argv[i][9],
 					"MaxNodes", &min, &max, true);
-				part_msg.max_nodes = min;
+				part_msg_ptr->max_nodes = min;
 			}
-			update_cnt++;
+			(*update_cnt_ptr)++;
 		}
 		else if (strncasecmp(argv[i], "MinNodes=", 9) == 0) {
 			min = 1;
 			get_resource_arg_range(&argv[i][9],
 				"MinNodes", &min, &max, true);
-			part_msg.min_nodes = min;
-			update_cnt++;
+			part_msg_ptr->min_nodes = min;
+			(*update_cnt_ptr)++;
 		}
 		else if (strncasecmp(argv[i], "Default=", 8) == 0) {
 			if (strcasecmp(&argv[i][8], "NO") == 0)
-				part_msg.default_part = 0;
+				part_msg_ptr->default_part = 0;
 			else if (strcasecmp(&argv[i][8], "YES") == 0)
-				part_msg.default_part = 1;
+				part_msg_ptr->default_part = 1;
 			else {
 				exit_code = 1;
 				error("Invalid input: %s", argv[i]);
 				error("Acceptable Default values "
 					"are YES and NO");
-				return 0;
+				return -1;
 			}
-			update_cnt++;
+			(*update_cnt_ptr)++;
 		}
 		else if (strncasecmp(argv[i], "Hidden=", 4) == 0) {
 			if (strcasecmp(&argv[i][7], "NO") == 0)
-				part_msg.hidden = 0;
+				part_msg_ptr->hidden = 0;
 			else if (strcasecmp(&argv[i][7], "YES") == 0)
-				part_msg.hidden = 1;
+				part_msg_ptr->hidden = 1;
 			else {
 				exit_code = 1;
 				error("Invalid input: %s", argv[i]);
 				error("Acceptable Hidden values "
 					"are YES and NO");
-				return 0;
+				return -1;
 			}
-			update_cnt++;
+			(*update_cnt_ptr)++;
 		}
 		else if (strncasecmp(argv[i], "RootOnly=", 4) == 0) {
 			if (strcasecmp(&argv[i][9], "NO") == 0)
-				part_msg.root_only = 0;
+				part_msg_ptr->root_only = 0;
 			else if (strcasecmp(&argv[i][9], "YES") == 0)
-				part_msg.root_only = 1;
+				part_msg_ptr->root_only = 1;
 			else {
 				exit_code = 1;
 				error("Invalid input: %s", argv[i]);
 				error("Acceptable RootOnly values "
 					"are YES and NO");
-				return 0;
+				return -1;
 			}
-			update_cnt++;
+			(*update_cnt_ptr)++;
 		}
 		else if (strncasecmp(argv[i], "Shared=", 7) == 0) {
 			if (strncasecmp(&argv[i][7], "NO", 2) == 0) {
-				part_msg.max_share = 1;
+				part_msg_ptr->max_share = 1;
 			} else if (strncasecmp(&argv[i][7], "EXCLUSIVE", 9) == 0) {
-				part_msg.max_share = 0;
+				part_msg_ptr->max_share = 0;
 			} else if (strncasecmp(&argv[i][7], "YES:", 4) == 0) {
-				part_msg.max_share = (uint16_t) strtol(&argv[i][11], 
+				part_msg_ptr->max_share = (uint16_t) strtol(&argv[i][11], 
 					(char **) NULL, 10);
 			} else if (strncasecmp(&argv[i][7], "YES", 3) == 0) {
-				part_msg.max_share = (uint16_t) 4;
+				part_msg_ptr->max_share = (uint16_t) 4;
 			} else if (strncasecmp(&argv[i][7], "FORCE:", 6) == 0) {
-				part_msg.max_share = (uint16_t) strtol(&argv[i][13],
+				part_msg_ptr->max_share = (uint16_t) strtol(&argv[i][13],
 					(char **) NULL, 10) | SHARED_FORCE;
 			} else if (strncasecmp(&argv[i][7], "FORCE", 5) == 0) {
-				part_msg.max_share = (uint16_t) 4 |
+				part_msg_ptr->max_share = (uint16_t) 4 |
 					SHARED_FORCE;
 			} else {
 				exit_code = 1;
 				error("Invalid input: %s", argv[i]);
 				error("Acceptable Shared values are "
 					"NO, EXCLUSIVE, YES:#, and FORCE:#");
-				return 0;
+				return -1;
 			}
-			update_cnt++;
+			(*update_cnt_ptr)++;
 		}
 		else if (strncasecmp(argv[i], "Priority=", 9) == 0) {
-			part_msg.priority = (uint16_t) strtol(&argv[i][9], 
+			part_msg_ptr->priority = (uint16_t) strtol(&argv[i][9], 
 					(char **) NULL, 10);
-			update_cnt++;
+			(*update_cnt_ptr)++;
 		}
 		else if (strncasecmp(argv[i], "State=", 6) == 0) {
 			if (strcasecmp(&argv[i][6], "DOWN") == 0)
-				part_msg.state_up = 0;
+				part_msg_ptr->state_up = 0;
 			else if (strcasecmp(&argv[i][6], "UP") == 0)
-				part_msg.state_up = 1;
+				part_msg_ptr->state_up = 1;
 			else {
 				exit_code = 1;
 				error("Invalid input: %s", argv[i]);
 				error("Acceptable State values "
 					"are UP and DOWN");
-				return 0;
+				return -1;
 			}
-			update_cnt++;
+			(*update_cnt_ptr)++;
 		}
 		else if (strncasecmp(argv[i], "Nodes=", 6) == 0) {
-			part_msg.nodes = &argv[i][6];
-			update_cnt++;
+			part_msg_ptr->nodes = &argv[i][6];
+			(*update_cnt_ptr)++;
 		}
 		else if (strncasecmp(argv[i], "AllowGroups=", 12) == 0) {
-			part_msg.allow_groups = &argv[i][12];
-			update_cnt++;
+			part_msg_ptr->allow_groups = &argv[i][12];
+			(*update_cnt_ptr)++;
 		}
 		else {
 			exit_code = 1;
 			error("Invalid input: %s", argv[i]);
 			error("Request aborted");
-			return 0;
+			return -1;
 		}
 	}
+	return 0;
+}
+
+
+
+/* 
+ * scontrol_update_part - update the slurm partition configuration per the 
+ *	supplied arguments 
+ * IN argc - count of arguments
+ * IN argv - list of arguments
+ * RET 0 if no slurm error, errno otherwise. parsing error prints 
+ *			error message and returns 0
+ */
+extern int
+scontrol_update_part (int argc, char *argv[]) 
+{
+	int update_cnt = 0;
+	update_part_msg_t part_msg;
+
+	slurm_init_part_desc_msg ( &part_msg );
+	scontrol_parse_part_options (argc, argv, &update_cnt, &part_msg);
+
+	if (exit_code != 0)
+		return 0;
 
 	if (update_cnt == 0) {
 		exit_code = 1;
@@ -200,3 +226,40 @@ scontrol_update_part (int argc, char *argv[])
 	} else
 		return 0;
 }
+
+
+
+/* 
+ * scontrol_create_part - create a slurm partition configuration per the 
+ *	supplied arguments 
+ * IN argc - count of arguments
+ * IN argv - list of arguments
+ * RET 0 if no slurm error, errno otherwise. parsing error prints 
+ *			error message and returns 0
+ */
+extern int
+scontrol_create_part (int argc, char *argv[]) 
+{
+	int update_cnt = 0;
+	update_part_msg_t part_msg;
+
+	slurm_init_part_desc_msg ( &part_msg );
+	scontrol_parse_part_options (argc, argv, &update_cnt, &part_msg);
+
+	if (exit_code != 0)
+		return 0;
+
+	if (slurm_create_partition(&part_msg)) {
+		exit_code = 1;
+		return slurm_get_errno ();
+	}
+	return 0;
+}
+
+
+
+
+
+
+
+
diff --git a/src/slurmctld/partition_mgr.c b/src/slurmctld/partition_mgr.c
index 6952c03ebc6..fd8a2601c30 100644
--- a/src/slurmctld/partition_mgr.c
+++ b/src/slurmctld/partition_mgr.c
@@ -299,6 +299,8 @@ int dump_all_part_state(void)
 	/* write partition records to buffer */
 	lock_slurmctld(part_read_lock);
 	part_iterator = list_iterator_create(part_list);
+	if (!part_iterator)
+		fatal("list_iterator_create malloc");
 	while ((part_ptr = (struct part_record *) list_next(part_iterator))) {
 		xassert (part_ptr->magic == PART_MAGIC);
 		_dump_part_state(part_ptr, buffer);
@@ -714,7 +716,7 @@ extern void pack_all_part(char **buffer_ptr, int *buffer_size,
 
 	buffer = init_buf(BUF_SIZE);
 
-	/* write haeader: version and time */
+	/* write header: version and time */
 	parts_packed = 0;
 	pack32(parts_packed, buffer);
 	pack_time(now, buffer);
@@ -750,8 +752,8 @@ extern void pack_all_part(char **buffer_ptr, int *buffer_size,
  * IN/OUT buffer - buffer in which data is placed, pointers automatically 
  *	updated
  * global: default_part_loc - pointer to the default partition
- * NOTE: if you make any changes here be sure to make the corresponding 
- *	changes to load_part_config in api/partition_info.c
+ * NOTE: if you make any changes here be sure to make the corresponding changes
+ *	to _unpack_partition_info_members() in common/slurm_protocol_pack.c
  */
 void pack_part(struct part_record *part_ptr, Buf buffer)
 {
diff --git a/src/slurmctld/proc_req.c b/src/slurmctld/proc_req.c
index 64fc8fba033..ab148171ae4 100644
--- a/src/slurmctld/proc_req.c
+++ b/src/slurmctld/proc_req.c
@@ -2,7 +2,7 @@
  *  proc_req.c - process incomming messages to slurmctld
  *****************************************************************************
  *  Copyright (C) 2002-2007 The Regents of the University of California.
- *  Copyright (C) 2008 Lawrence Livermore National Security.
+ *  Copyright (C) 2008-2009 Lawrence Livermore National Security.
  *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
  *  Written by Morris Jette <jette@llnl.gov>, et. al. 
  *  LLNL-CODE-402394.
@@ -75,6 +75,7 @@
 #include "src/slurmctld/locks.h"
 #include "src/slurmctld/proc_req.h"
 #include "src/slurmctld/read_config.h"
+#include "src/slurmctld/reservation.h"
 #include "src/slurmctld/sched_plugin.h"
 #include "src/slurmctld/slurmctld.h"
 #include "src/slurmctld/srun_comm.h"
@@ -113,6 +114,10 @@ inline static void  _slurm_rpc_job_alloc_info(slurm_msg_t * msg);
 inline static void  _slurm_rpc_job_alloc_info_lite(slurm_msg_t * msg);
 inline static void  _slurm_rpc_ping(slurm_msg_t * msg);
 inline static void  _slurm_rpc_reconfigure_controller(slurm_msg_t * msg);
+inline static void  _slurm_rpc_resv_create(slurm_msg_t * msg);
+inline static void  _slurm_rpc_resv_update(slurm_msg_t * msg);
+inline static void  _slurm_rpc_resv_delete(slurm_msg_t * msg);
+inline static void  _slurm_rpc_resv_show(slurm_msg_t * msg);
 inline static void  _slurm_rpc_requeue(slurm_msg_t * msg);
 inline static void  _slurm_rpc_shutdown_controller(slurm_msg_t * msg);
 inline static void  _slurm_rpc_shutdown_controller_immediate(slurm_msg_t *
@@ -253,6 +258,7 @@ void slurmctld_req (slurm_msg_t * msg)
 		_slurm_rpc_update_node(msg);
 		slurm_free_update_node_msg(msg->data);
 		break;
+	case REQUEST_CREATE_PARTITION:
 	case REQUEST_UPDATE_PARTITION:
 		_slurm_rpc_update_partition(msg);
 		slurm_free_update_part_msg(msg->data);
@@ -261,6 +267,22 @@ void slurmctld_req (slurm_msg_t * msg)
 		_slurm_rpc_delete_partition(msg);
 		slurm_free_delete_part_msg(msg->data);
 		break;
+	case REQUEST_CREATE_RESERVATION:
+		_slurm_rpc_resv_create(msg);
+		slurm_free_update_resv_msg(msg->data);
+		break;
+	case REQUEST_UPDATE_RESERVATION:
+		_slurm_rpc_resv_update(msg);
+		slurm_free_update_resv_msg(msg->data);
+		break;
+	case REQUEST_DELETE_RESERVATION:
+		_slurm_rpc_resv_delete(msg);
+		slurm_free_resv_name_msg(msg->data);
+		break;
+	case REQUEST_RESERVATION_INFO:
+		_slurm_rpc_resv_show(msg);
+		/* No body to free */
+		break;
 	case REQUEST_NODE_REGISTRATION_STATUS:
 		error("slurmctld is talking with itself. "
 			"SlurmctldPort == SlurmdPort");
@@ -2323,6 +2345,204 @@ static void _slurm_rpc_delete_partition(slurm_msg_t * msg)
 	}
 }
 
+/* _slurm_rpc_resv_create - process RPC to create a reservation */
+static void _slurm_rpc_resv_create(slurm_msg_t * msg)
+{
+	int error_code = SLURM_SUCCESS;
+	DEF_TIMERS;
+	reserve_request_msg_t *resv_desc_ptr = (reserve_request_msg_t *) 
+						msg->data;
+	/* Locks: write node, read partition */
+	slurmctld_lock_t node_write_lock = { 
+		NO_LOCK, NO_LOCK, WRITE_LOCK, READ_LOCK };
+	uid_t uid = g_slurm_auth_get_uid(msg->auth_cred, NULL);
+
+	START_TIMER;
+	debug2("Processing RPC: REQUEST_CREATE_RESERVATION from uid=%u",
+		(unsigned int) uid);
+	if (!validate_super_user(uid)) {
+		error_code = ESLURM_USER_ID_MISSING;
+		error
+		    ("Security violation, CREATE_RESERVATION RPC from uid=%u",
+		     (unsigned int) uid);
+	}
+
+	if (error_code == SLURM_SUCCESS) {
+		/* do RPC call */
+		lock_slurmctld(node_write_lock);
+		error_code = create_resv(resv_desc_ptr);
+		unlock_slurmctld(node_write_lock);
+		END_TIMER2("_slurm_rpc_resv_create");
+	}
+
+	/* return result */
+	if (error_code) {
+		info("_slurm_rpc_resv_create reservation=%s: %s",
+			resv_desc_ptr->name, slurm_strerror(error_code));
+		slurm_send_rc_msg(msg, error_code);
+	} else {
+		slurm_msg_t response_msg;
+		reservation_name_msg_t resv_resp_msg;
+
+		debug2("_slurm_rpc_resv_create complete for %s %s",
+			resv_desc_ptr->name, TIME_STR);
+		/* send reservation name */
+		slurm_msg_t_init(&response_msg);
+		resv_resp_msg.name    = resv_desc_ptr->name;
+		response_msg.msg_type = RESPONSE_CREATE_RESERVATION;
+		response_msg.data     = &resv_resp_msg;
+		slurm_send_node_msg(msg->conn_fd, &response_msg);
+
+		/* NOTE: These functions provide their own locks */
+		if (schedule()) {
+			schedule_job_save();
+			schedule_node_save();
+		}
+	}
+}
+
+/* _slurm_rpc_resv_update - process RPC to update a reservation */
+static void _slurm_rpc_resv_update(slurm_msg_t * msg)
+{
+	int error_code = SLURM_SUCCESS;
+	DEF_TIMERS;
+	reserve_request_msg_t *resv_desc_ptr = (reserve_request_msg_t *) 
+						msg->data;
+	/* Locks: write node, read partition */
+	slurmctld_lock_t node_write_lock = { 
+		NO_LOCK, NO_LOCK, WRITE_LOCK, READ_LOCK };
+	uid_t uid = g_slurm_auth_get_uid(msg->auth_cred, NULL);
+
+	START_TIMER;
+	debug2("Processing RPC: REQUEST_UPDATE_RESERVATION from uid=%u",
+		(unsigned int) uid);
+	if (!validate_super_user(uid)) {
+		error_code = ESLURM_USER_ID_MISSING;
+		error
+		    ("Security violation, UPDATE_RESERVATION RPC from uid=%u",
+		     (unsigned int) uid);
+	}
+
+	if (error_code == SLURM_SUCCESS) {
+		/* do RPC call */
+		lock_slurmctld(node_write_lock);
+		error_code = update_resv(resv_desc_ptr);
+		unlock_slurmctld(node_write_lock);
+		END_TIMER2("_slurm_rpc_resv_update");
+	}
+
+	/* return result */
+	if (error_code) {
+		info("_slurm_rpc_resv_update reservation=%s: %s",
+			resv_desc_ptr->name, slurm_strerror(error_code));
+		slurm_send_rc_msg(msg, error_code);
+	} else {
+		debug2("_slurm_rpc_resv_update complete for %s %s",
+			resv_desc_ptr->name, TIME_STR);
+		slurm_send_rc_msg(msg, SLURM_SUCCESS);
+
+		/* NOTE: These functions provide their own locks */
+		if (schedule()) {
+			schedule_job_save();
+			schedule_node_save();
+		}
+	}
+}
+
+/* _slurm_rpc_resv_delete - process RPC to delete a reservation */
+static void _slurm_rpc_resv_delete(slurm_msg_t * msg)
+{
+	/* init */
+	int error_code = SLURM_SUCCESS;
+	DEF_TIMERS;
+	reservation_name_msg_t *resv_desc_ptr = (reservation_name_msg_t *)
+					      msg->data;
+	/* Locks: write node */
+	slurmctld_lock_t node_write_lock = { 
+		NO_LOCK, NO_LOCK, WRITE_LOCK, NO_LOCK };
+	uid_t uid = g_slurm_auth_get_uid(msg->auth_cred, NULL);
+
+	START_TIMER;
+	debug2("Processing RPC: REQUEST_DELETE_RESERVTION from uid=%u",
+		(unsigned int) uid);
+	if (!validate_super_user(uid)) {
+		error_code = ESLURM_USER_ID_MISSING;
+		error
+		    ("Security violation, DELETE_RESERVTION RPC from uid=%u",
+		     (unsigned int) uid);
+	}
+
+	if (error_code == SLURM_SUCCESS) {
+		/* do RPC call */
+		lock_slurmctld(node_write_lock);
+		error_code = delete_resv(resv_desc_ptr);
+		unlock_slurmctld(node_write_lock);
+		END_TIMER2("_slurm_rpc_resv_delete");
+	}
+
+	/* return result */
+	if (error_code) {
+		info("_slurm_rpc_delete_reservation partition=%s: %s",
+			resv_desc_ptr->name, slurm_strerror(error_code));
+		slurm_send_rc_msg(msg, error_code);
+	} else {
+		info("_slurm_rpc_delete_reservation complete for %s %s",
+			resv_desc_ptr->name, TIME_STR);
+		slurm_send_rc_msg(msg, SLURM_SUCCESS);
+
+		/* NOTE: These functions provide their own locks */
+		if (schedule()) {
+			schedule_job_save();
+			schedule_node_save();
+		}
+
+	}
+}
+
+/* _slurm_rpc_resv_show - process RPC to dump reservation info */
+static void _slurm_rpc_resv_show(slurm_msg_t * msg)
+{
+        resv_info_request_msg_t *resv_req_msg = (resv_info_request_msg_t *) 
+						msg->data;
+	DEF_TIMERS;
+	/* Locks: read node */
+	slurmctld_lock_t node_read_lock = { 
+		NO_LOCK, NO_LOCK, READ_LOCK, NO_LOCK };
+	uid_t uid = g_slurm_auth_get_uid(msg->auth_cred, NULL);
+	slurm_msg_t response_msg;
+	char *dump;
+	int dump_size;
+
+	START_TIMER;
+	debug2("Processing RPC: REQUEST_RESERVATION_INFO from uid=%u",
+		(unsigned int) uid);
+	if ((slurmctld_conf.private_data & PRIVATE_DATA_PARTITIONS) &&
+	    (!validate_super_user(uid))) {
+		debug2("Security violation, REQUEST_RESERVATION_INFO "
+		       "RPC from uid=%d", uid);
+		slurm_send_rc_msg(msg, ESLURM_ACCESS_DENIED);
+	} else if ((resv_req_msg->last_update - 1) >= last_resv_update) {
+		debug2("_slurm_rpc_resv_show, no change");
+		slurm_send_rc_msg(msg, SLURM_NO_CHANGE_IN_DATA);
+	} else {
+		lock_slurmctld(node_read_lock);
+		show_resv(&dump, &dump_size, uid);
+		unlock_slurmctld(node_read_lock);
+		END_TIMER2("_slurm_rpc_resv_show");
+
+		/* init response_msg structure */
+		slurm_msg_t_init(&response_msg);
+		response_msg.address = msg->address;
+		response_msg.msg_type = RESPONSE_RESERVATION_INFO;
+		response_msg.data = dump;
+		response_msg.data_size = dump_size;
+
+		/* send message */
+		slurm_send_node_msg(msg->conn_fd, &response_msg);
+		xfree(dump);
+	}
+}
+
 /* determine of nodes are ready for the job */
 static void _slurm_rpc_job_ready(slurm_msg_t * msg)
 {
diff --git a/src/slurmctld/read_config.c b/src/slurmctld/read_config.c
index d77b249c397..50a2cf62295 100644
--- a/src/slurmctld/read_config.c
+++ b/src/slurmctld/read_config.c
@@ -76,6 +76,7 @@
 #include "src/slurmctld/node_scheduler.h"
 #include "src/slurmctld/proc_req.h"
 #include "src/slurmctld/read_config.h"
+#include "src/slurmctld/reservation.h"
 #include "src/slurmctld/sched_plugin.h"
 #include "src/slurmctld/slurmctld.h"
 #include "src/slurmctld/trigger_mgr.h"
@@ -854,6 +855,7 @@ int read_slurm_conf(int recover)
 	(void) _sync_nodes_to_comp_job();/* must follow select_g_node_init() */
 	load_part_uid_allow_list(1);
 
+	load_all_resv_state(recover);
 	if (recover >= 1)
 		(void) trigger_state_restore();
 
diff --git a/src/slurmctld/reservation.c b/src/slurmctld/reservation.c
index cdc60b33254..faee8bbbe47 100644
--- a/src/slurmctld/reservation.c
+++ b/src/slurmctld/reservation.c
@@ -15,7 +15,7 @@
  *  any later version.
  *
  *  In addition, as a special exception, the copyright holders give permission 
- *  to link the code of portions of this program with the OpenSSL library under 
+ *  to link the code of portions of this program with the OpenSSL library under
  *  certain conditions as described in each individual source file, and 
  *  distribute linked combinations including the two. You must obey the GNU 
  *  General Public License in all respects for all of the code used other than 
@@ -35,4 +35,1288 @@
  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA.
 \*****************************************************************************/
 
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
 
+#ifdef WITH_PTHREADS
+#  include <pthread.h>
+#endif				/* WITH_PTHREADS */
+
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+#include <slurm/slurm.h>
+#include <slurm/slurm_errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "src/common/bitstring.h"
+#include "src/common/hostlist.h"
+#include "src/common/list.h"
+#include "src/common/log.h"
+#include "src/common/macros.h"
+#include "src/common/pack.h"
+#include "src/common/parse_time.h"
+#include "src/common/uid.h"
+#include "src/common/xassert.h"
+#include "src/common/xmalloc.h"
+#include "src/common/xstring.h"
+
+#include "src/slurmctld/locks.h"
+#include "src/slurmctld/slurmctld.h"
+#include "src/slurmctld/state_save.h"
+
+#define _RESV_DEBUG	1
+#define RESV_MAGIC	0x3b82
+
+/* Change RESV_STATE_VERSION value when changing the state save format */
+#define RESV_STATE_VERSION      "VER001"
+
+time_t last_resv_update = (time_t) 0;
+
+typedef struct slurmctld_resv {
+	char *accounts;		/* names of accounts permitted to use	*/
+	int account_cnt;	/* count of accounts permitted to use	*/
+	char **account_list;	/* list of accounts permitted to use	*/
+	char *assoc_list;	/* list of associations			*/
+	uint32_t cpu_cnt;	/* number of reserved CPUs		*/
+	time_t end_time;	/* end time of reservation		*/
+	char *features;		/* required node features		*/
+	uint16_t magic;		/* magic cookie, RESV_MAGIC		*/
+	char *name;		/* name of reservation			*/
+	uint32_t node_cnt;	/* count of nodes required		*/
+	char *node_list;	/* list of reserved nodes or ALL	*/
+	bitstr_t *node_bitmap;	/* bitmap of reserved nodes		*/
+	char *partition;	/* name of partition to be used		*/
+	struct part_record *part_ptr;	/* pointer to partition used	*/
+	uint32_t resv_id;	/* unique reservation ID, internal use	*/
+	time_t start_time;	/* start time of reservation		*/
+	uint16_t type;		/* see RESERVE_TYPE_* above		*/
+	char *users;		/* names of users permitted to use	*/
+	int user_cnt;		/* count of users permitted to use	*/
+	uid_t *user_list;	/* array of users permitted to use	*/
+} slurmctld_resv_t;
+
+List     resv_list = (List) NULL;
+uint32_t top_suffix = 0;
+
+static int  _build_account_list(char *accounts, int *account_cnt, 
+			        char ***account_list);
+static int  _build_uid_list(char *users, int *user_cnt, uid_t **user_list);
+static void _del_resv_rec(void *x);
+static void _deleted_resv(struct slurmctld_resv *resv_ptr);
+static void _dump_resv_req(reserve_request_msg_t *resv_ptr, char *mode);
+static int  _find_resv_name(void *x, void *key);
+static void _generate_resv_name(reserve_request_msg_t *resv_ptr);
+static bool _is_account_valid(char *account);
+static void _pack_resv(struct slurmctld_resv *resv_ptr, Buf buffer,
+		       bool internal);
+static void _set_assoc_list(struct slurmctld_resv *resv_ptr);
+static void _set_resv_id(struct slurmctld_resv *resv_ptr);
+static int  _update_account_list(struct slurmctld_resv *resv_ptr, 
+				 char *accounts);
+static int  _update_uid_list(struct slurmctld_resv *resv_ptr, char *users);
+static void _updated_resv(struct slurmctld_resv *resv_ptr);
+static void _validate_all_reservations(void);
+static bool _validate_one_reservation(slurmctld_resv_t *resv_ptr);
+
+
+static void _del_resv_rec(void *x)
+{
+	int i;
+	slurmctld_resv_t *resv_ptr = (slurmctld_resv_t *) x;
+
+	if (resv_ptr) {
+		xassert(resv_ptr->magic == RESV_MAGIC);
+		xfree(resv_ptr->accounts);
+		for (i=0; i<resv_ptr->account_cnt; i++)
+			xfree(resv_ptr->account_list[i]);
+		xfree(resv_ptr->account_list);
+		xfree(resv_ptr->assoc_list);
+		xfree(resv_ptr->features);
+		xfree(resv_ptr->name);
+		if (resv_ptr->node_bitmap)
+			bit_free(resv_ptr->node_bitmap);
+		xfree(resv_ptr->node_list);
+		xfree(resv_ptr->partition);
+		xfree(resv_ptr->users);
+		xfree(resv_ptr->user_list);
+		xfree(resv_ptr);
+	}
+}
+
+static int _find_resv_name(void *x, void *key)
+{
+	slurmctld_resv_t *resv_ptr = (slurmctld_resv_t *) x;
+
+	xassert(resv_ptr->magic == RESV_MAGIC);
+
+	if (strcmp(resv_ptr->name, (char *) key))
+		return 0;
+	else
+		return 1;	/* match */
+}
+
+static void _dump_resv_req(reserve_request_msg_t *resv_ptr, char *mode)
+{
+#ifdef _RESV_DEBUG
+	char start_str[32] = "", end_str[32] = "", *type_str;
+	int duration;
+
+	slurm_make_time_str(&resv_ptr->start_time,start_str,sizeof(start_str));
+	slurm_make_time_str(&resv_ptr->end_time,  end_str,  sizeof(end_str));
+	if (resv_ptr->type == RESERVE_TYPE_MAINT)
+		type_str = "MAINT";
+	else
+		type_str = "";
+	if (resv_ptr->duration == NO_VAL)
+		duration = -1;
+	else
+		duration = resv_ptr->duration;
+
+	info("%s: Name=%s StartTime=%s EndTime=%s Duration=%d "
+	     "Type=%s NodeCnt=%u NodeList=%s Features=%s "
+	     "PartitionName=%s Users=%s Accounts=%s",
+	     mode, resv_ptr->name, start_str, end_str, duration,
+	     type_str, resv_ptr->node_cnt, resv_ptr->node_list, 
+	     resv_ptr->features, resv_ptr->partition, 
+	     resv_ptr->users, resv_ptr->accounts);
+#endif
+}
+
+static void _generate_resv_name(reserve_request_msg_t *resv_ptr)
+{
+	char *key, *name, *sep, tmp[32];
+	int len;
+
+	/* Generate name prefix, based upon the first account
+	 * name if provided otherwise first user name */
+	if (resv_ptr->accounts && resv_ptr->accounts[0])
+		key = resv_ptr->accounts;
+	else
+		key = resv_ptr->users;
+	sep = strchr(key, ',');
+	if (sep)
+		len = sep - key;
+	else
+		len = strlen(key);
+	name = xmalloc(len + 16);
+	strncpy(name, key, len);
+	strcat(name, "_");
+	len++;
+
+	if (top_suffix > 0xffffff00)
+		top_suffix = 0;	/* Wrap around */
+	snprintf(tmp, sizeof(tmp), "%d", ++top_suffix);
+	strcat(name, tmp);
+	resv_ptr->name = name;
+}
+
+/* Validate an account name */
+static bool _is_account_valid(char *account)
+{
+	/* FIXME: Need to add logic here */
+	return true;
+}
+
+/* Set a association list based upon accounts and users */
+static void _set_assoc_list(struct slurmctld_resv *resv_ptr)
+{
+	/* FIXME: Need to add logic here to get assoc_list from slurmdbd
+	 * based upon resv_ptr->account_cnt and account_list plus
+	 * user_cnt and user_list */
+	xfree(resv_ptr->assoc_list);	/* clear for modify */
+	resv_ptr->assoc_list = xstrdup("TBD");	/* FOR TESTING ONLY */
+}
+
+/* Set a unique reservation id */
+static void _set_resv_id(struct slurmctld_resv *resv_ptr)
+{
+	/* FIXME: Need to add logic here to get resv_id from slurmdbd */
+	/* NOTE: resv_id is zero on entry */
+	resv_ptr->resv_id = top_suffix;	/* FOR TESTING ONLY */
+}
+
+/* Note that a reservation has been deleted */
+static void _deleted_resv(struct slurmctld_resv *resv_ptr)
+{
+	/* FIXME: Need to add logic here to notify slurmdbd */
+}
+
+/* Note that a reservation has been updated */
+static void _updated_resv(struct slurmctld_resv *resv_ptr)
+{
+	/* FIXME: Need to add logic here to notify slurmdbd */
+}
+
+/*
+ * Validate a comma delimited list of account names and build an array of
+ *	them
+ * IN account       - a list of account names
+ * OUT account_cnt  - number of accounts in the list
+ * OUT account_list - list of the account names, 
+ *		      CALLER MUST XFREE this plus each individual record
+ * RETURN 0 on success
+ */
+static int _build_account_list(char *accounts, int *account_cnt, 
+			       char ***account_list)
+{
+	char *last, *tmp, *tok;
+	int ac_cnt = 0, i;
+	char **ac_list;
+
+	*account_cnt = 0;
+	*account_list = (char **) NULL;
+
+	if (!accounts)
+		return ESLURM_INVALID_BANK_ACCOUNT;
+
+	i = strlen(accounts);
+	ac_list = xmalloc(sizeof(char *) * (i + 2));
+	tmp = xstrdup(accounts);
+	tok = strtok_r(tmp, ",", &last);
+	while (tok) {
+		if (!_is_account_valid(tok)) {
+			info("Reservation request has invalid account %s", 
+			     tok);
+			goto inval;
+		}
+		ac_list[ac_cnt++] = xstrdup(tok);
+		tok = strtok_r(NULL, ",", &last);
+	}
+	*account_cnt  = ac_cnt;
+	*account_list = ac_list;
+	xfree(tmp);
+	return SLURM_SUCCESS;
+
+ inval:	for (i=0; i<ac_cnt; i++)
+		xfree(ac_list[i]);
+	xfree(ac_list);
+	xfree(tmp);
+	return ESLURM_INVALID_BANK_ACCOUNT;
+}
+
+/*
+ * Update a account list for an existing reservation based upon an 
+ *	update comma delimited specification of accounts to add (+name), 
+ *	remove (-name), or set value of
+ * IN/OUT resv_ptr - pointer to reservation structure being updated
+ * IN accounts     - a list of account names, to set, add, or remove
+ * RETURN 0 on success
+ */
+static int  _update_account_list(struct slurmctld_resv *resv_ptr, 
+				 char *accounts)
+{
+	char *last, *tmp, *tok;
+	int ac_cnt = 0, i, j, k;
+	int *ac_type, minus_account = 0, plus_account = 0;
+	char **ac_list;
+	bool found_it;
+
+	if (!accounts)
+		return ESLURM_INVALID_BANK_ACCOUNT;
+
+	i = strlen(accounts);
+	ac_list = xmalloc(sizeof(char *) * (i + 2));
+	ac_type = xmalloc(sizeof(int)    * (i + 2));
+	tmp = xstrdup(accounts);
+	tok = strtok_r(tmp, ",", &last);
+	while (tok) {
+		if (tok[0] == '-') {
+			ac_type[ac_cnt] = 1;	/* minus */
+			minus_account = 1;
+			tok++;
+		} else if (tok[0] == '+') {
+			ac_type[ac_cnt] = 2;	/* plus */
+			plus_account = 1;
+			tok++;
+		} else if (plus_account || minus_account) {
+			info("Reservation account expression invalid %s", 
+			     accounts);
+			goto inval;
+		} else
+			ac_type[ac_cnt] = 3;	/* set */
+		if (!_is_account_valid(tok)) {
+			info("Reservation request has invalid account %s", 
+			     tok);
+			goto inval;
+		}
+		ac_list[ac_cnt++] = xstrdup(tok);
+		tok = strtok_r(NULL, ",", &last);
+	}
+	xfree(tmp);
+
+	if ((plus_account == 0) && (minus_account == 0)) {
+		/* Just a reset of account list */
+		xfree(resv_ptr->accounts);
+		resv_ptr->accounts = xstrdup(accounts);
+		xfree(resv_ptr->account_list);
+		resv_ptr->account_list = ac_list;
+		resv_ptr->account_cnt = ac_cnt;
+		xfree(ac_type);
+		return SLURM_SUCCESS;
+	}
+
+	/* Modification of existing account list */
+	if (minus_account) {
+		if (resv_ptr->account_cnt == 0)
+			goto inval;
+		for (i=0; i<ac_cnt; i++) {
+			if (ac_type[i] != 1)
+				continue;
+			found_it = false;
+			for (j=0; j<resv_ptr->account_cnt; j++) {
+				if (strcmp(resv_ptr->account_list[j], 
+					   ac_list[i])) {
+					continue;
+				}
+				found_it = true;
+				xfree(resv_ptr->account_list[j]);
+				resv_ptr->account_cnt--;
+				for (k=j; k<resv_ptr->account_cnt; k++) {
+					resv_ptr->account_list[k] =
+						resv_ptr->account_list[k+1];
+				}
+				break;
+			}
+			if (!found_it)
+				goto inval;
+		}
+		xfree(resv_ptr->accounts);
+		for (i=0; i<resv_ptr->account_cnt; i++) {
+			if (i == 0) {
+				resv_ptr->accounts = xstrdup(resv_ptr->
+							     account_list[i]);
+			} else {
+				xstrcat(resv_ptr->accounts, ",");
+				xstrcat(resv_ptr->accounts,
+					resv_ptr->account_list[i]);
+			}
+		}
+	}
+
+	if (plus_account) {
+		for (i=0; i<ac_cnt; i++) {
+			if (ac_type[i] != 2)
+				continue;
+			found_it = false;
+			for (j=0; j<resv_ptr->account_cnt; j++) {
+				if (strcmp(resv_ptr->account_list[j], 
+					   ac_list[i])) {
+					continue;
+				}
+				found_it = true;
+				break;
+			}
+			if (found_it)
+				continue;	/* duplicate entry */
+			xrealloc(resv_ptr->account_list, 
+				 sizeof(char *) * (resv_ptr->account_cnt + 1));
+			resv_ptr->account_list[resv_ptr->account_cnt++] =
+					xstrdup(ac_list[i]);
+		}
+		xfree(resv_ptr->accounts);
+		for (i=0; i<resv_ptr->account_cnt; i++) {
+			if (i == 0) {
+				resv_ptr->accounts = xstrdup(resv_ptr->
+							     account_list[i]);
+			} else {
+				xstrcat(resv_ptr->accounts, ",");
+				xstrcat(resv_ptr->accounts,
+					resv_ptr->account_list[i]);
+			}
+		}
+	}
+	for (i=0; i<ac_cnt; i++)
+		xfree(ac_list[i]);
+	xfree(ac_list);
+	xfree(ac_type);
+	return SLURM_SUCCESS;
+
+ inval:	for (i=0; i<ac_cnt; i++)
+		xfree(ac_list[i]);
+	xfree(ac_list);
+	xfree(ac_type);
+	xfree(tmp);
+	return ESLURM_INVALID_BANK_ACCOUNT;
+}
+
+/*
+ * Validate a comma delimited list of user names and build an array of
+ *	their UIDs
+ * IN users      - a list of user names
+ * OUT user_cnt  - number of UIDs in the list
+ * OUT user_list - list of the user's uid, CALLER MUST XFREE;
+ * RETURN 0 on success
+ */
+static int _build_uid_list(char *users, int *user_cnt, uid_t **user_list)
+{
+	char *last, *tmp = NULL, *tok;
+	int u_cnt = 0, i;
+	uid_t *u_list, u_tmp;
+
+	*user_cnt = 0;
+	*user_list = (uid_t *) NULL;
+
+	if (!users)
+		return ESLURM_USER_ID_MISSING;
+
+	i = strlen(users);
+	u_list = xmalloc(sizeof(uid_t) * (i + 2));
+	tmp = xstrdup(users);
+	tok = strtok_r(tmp, ",", &last);
+	while (tok) {
+		u_tmp = uid_from_string(tok);
+		if (u_tmp == (uid_t) -1) {
+			info("Reservation request has invalid user %s", tok);
+			goto inval;
+		}
+		u_list[u_cnt++] = u_tmp;
+		tok = strtok_r(NULL, ",", &last);
+	}
+	*user_cnt  = u_cnt;
+	*user_list = u_list;
+	xfree(tmp);
+	return SLURM_SUCCESS;
+
+ inval:	xfree(tmp);
+	xfree(u_list);
+	return ESLURM_USER_ID_MISSING;
+}
+
+/*
+ * Update a user/uid list for an existing reservation based upon an 
+ *	update comma delimited specification of users to add (+name), 
+ *	remove (-name), or set value of
+ * IN/OUT resv_ptr - pointer to reservation structure being updated
+ * IN users        - a list of user names, to set, add, or remove
+ * RETURN 0 on success
+ */
+static int _update_uid_list(struct slurmctld_resv *resv_ptr, char *users)
+{
+	char *last, *tmp = NULL, *tok;
+	int u_cnt = 0, i, j, k;
+	uid_t *u_list, u_tmp;
+	int *u_type, minus_user = 0, plus_user = 0;
+	char **u_name;
+	bool found_it;
+
+	if (!users)
+		return ESLURM_USER_ID_MISSING;
+
+	/* Parse the incoming user expression */
+	i = strlen(users);
+	u_list = xmalloc(sizeof(uid_t)  * (i + 2));
+	u_name = xmalloc(sizeof(char *) * (i + 2));
+	u_type = xmalloc(sizeof(int)    * (i + 2));
+	tmp = xstrdup(users);
+	tok = strtok_r(tmp, ",", &last);
+	while (tok) {
+		if (tok[0] == '-') {
+			u_type[u_cnt] = 1;	/* minus */
+			minus_user = 1;
+			tok++;
+		} else if (tok[0] == '+') {
+			u_type[u_cnt] = 2;	/* plus */
+			plus_user = 1;
+			tok++;
+		} else if (plus_user || minus_user) {
+			info("Reservation user expression invalid %s", users);
+			goto inval;
+		} else
+			u_type[u_cnt] = 3;	/* set */
+		u_tmp = uid_from_string(tok);
+		if (u_tmp == (uid_t) -1) {
+			info("Reservation request has invalid user %s", tok);
+			goto inval;
+		}
+		u_name[u_cnt] = tok;
+		u_list[u_cnt++] = u_tmp;
+		tok = strtok_r(NULL, ",", &last);
+	}
+	xfree(tmp);
+
+	if ((plus_user == 0) && (minus_user == 0)) {
+		/* Just a reset of user list */
+		xfree(resv_ptr->users);
+		xfree(resv_ptr->user_list);
+		resv_ptr->users = xstrdup(users);
+		resv_ptr->user_cnt  = u_cnt;
+		resv_ptr->user_list = u_list;
+		xfree(u_name);
+		xfree(u_type);
+		return SLURM_SUCCESS;
+	}
+	
+	/* Modification of existing user list */
+	if (minus_user) {
+		for (i=0; i<u_cnt; i++) {
+			if (u_type[i] != 1)
+				continue;
+			found_it = false;
+			for (j=0; j<resv_ptr->user_cnt; j++) {
+				if (resv_ptr->user_list[j] != u_list[i])
+					continue;
+				found_it = true;
+				resv_ptr->user_cnt--;
+				for (k=j; k<resv_ptr->user_cnt; k++) {
+					resv_ptr->user_list[k] =
+						resv_ptr->user_list[k+1];
+				}
+				break;
+			}
+			if (!found_it)
+				goto inval;
+			/* Now we need to remove from users string */
+			k = strlen(u_name[i]);
+			tmp = resv_ptr->users;
+			while ((tok = strstr(tmp, u_name[i]))) {
+				if (((tok != resv_ptr->users) &&
+				     (tok[-1] != ',')) ||
+				    ((tok[k] != '\0') && (tok[k] != ','))) {
+					tmp = tok + 1;
+					continue;
+				}
+				if (tok[-1] == ',') {
+					tok--;
+					k++;
+				} else if (tok[k] == ',')
+					k++;
+				for (j=0; ; j++) {
+					tok[j] = tok[j+k];
+					if (tok[j] == '\0')
+						break;
+				}
+			}
+		}
+	}
+
+	if (plus_user) {
+		for (i=0; i<u_cnt; i++) {
+			if (u_type[i] != 2)
+				continue;
+			found_it = false;
+			for (j=0; j<resv_ptr->user_cnt; j++) {
+				if (resv_ptr->user_list[j] != u_list[i])
+					continue;
+				found_it = true;
+				break;
+			}
+			if (found_it)
+				continue;	/* duplicate entry */
+			if (resv_ptr->users && resv_ptr->users[0])
+				xstrcat(resv_ptr->users, ",");
+			xstrcat(resv_ptr->users, u_name[i]);
+			xrealloc(resv_ptr->user_list, 
+				 sizeof(uid_t) * (resv_ptr->user_cnt + 1));
+			resv_ptr->user_list[resv_ptr->user_cnt++] =
+				u_list[i];
+		}
+	}
+	xfree(u_list);
+	xfree(u_name);
+	xfree(u_type);
+	return SLURM_SUCCESS;
+
+ inval:	xfree(tmp);
+	xfree(u_list);
+	xfree(u_name);
+	xfree(u_type);
+	return ESLURM_USER_ID_MISSING;
+}
+
+/* 
+ * _pack_resv - dump all configuration information about a specific reservation
+ *	in machine independent form (for network transmission)
+ * IN resv_ptr - pointer to reservation for which information is requested
+ * IN/OUT buffer - buffer in which data is placed, pointers automatically 
+ *	updated
+ * IN internal   - true if for internal save state, false for xmit to users
+ * NOTE: if you make any changes here be sure to make the corresponding 
+ *	to _unpack_reserve_info_members() in common/slurm_protocol_pack.c
+ *	plus load_all_resv_state() below.
+ */
+static void _pack_resv(struct slurmctld_resv *resv_ptr, Buf buffer, 
+		       bool internal)
+{
+	packstr(resv_ptr->accounts,	buffer);
+	pack_time(resv_ptr->end_time,	buffer);
+	packstr(resv_ptr->features,	buffer);
+	packstr(resv_ptr->name,		buffer);
+	pack32(resv_ptr->node_cnt,	buffer);
+	packstr(resv_ptr->node_list,	buffer);
+	packstr(resv_ptr->partition,	buffer);
+	pack_time(resv_ptr->start_time,	buffer);
+	pack16(resv_ptr->type,		buffer);
+	packstr(resv_ptr->users,	buffer);
+
+	if (internal) {
+		packstr(resv_ptr->assoc_list,	buffer);
+		pack32(resv_ptr->cpu_cnt,	buffer);
+		pack32(resv_ptr->resv_id,	buffer);
+	}
+}
+
+/* Create a resource reservation */
+extern int create_resv(reserve_request_msg_t *resv_desc_ptr)
+{
+	int i, rc = SLURM_SUCCESS;
+	time_t now = time(NULL);
+	struct part_record *part_ptr = NULL;
+	bitstr_t *node_bitmap = NULL;
+	slurmctld_resv_t *resv_ptr;
+	int account_cnt = 0, user_cnt = 0;
+	char **account_list = NULL;
+	uid_t *user_list = NULL;
+
+	if (!resv_list)
+		resv_list = list_create(_del_resv_rec);
+	_dump_resv_req(resv_desc_ptr, "create_resv");
+
+	/* Validate the request */
+	if (resv_desc_ptr->start_time != (time_t) NO_VAL) {
+		if (resv_desc_ptr->start_time < (now - 60)) {
+			info("Reservation requestion has invalid start time");
+			rc = ESLURM_INVALID_TIME_VALUE;
+			goto bad_parse;
+		}
+	} else
+		resv_desc_ptr->start_time = now;
+	if (resv_desc_ptr->end_time != (time_t) NO_VAL) {
+		if (resv_desc_ptr->end_time < (now - 60)) {
+			info("Reservation requestion has invalid end time");
+			rc = ESLURM_INVALID_TIME_VALUE;
+			goto bad_parse;
+		}
+	} else if (resv_desc_ptr->duration) {
+		resv_desc_ptr->end_time = resv_desc_ptr->start_time +
+					  (resv_desc_ptr->duration * 60);
+	} else
+		resv_desc_ptr->end_time = INFINITE;
+	if (resv_desc_ptr->type == (uint16_t) NO_VAL)
+		resv_desc_ptr->type = 0;
+	else if (resv_desc_ptr->type > RESERVE_TYPE_MAINT) {
+		info("Invalid reservation type %u ignored",
+		      resv_desc_ptr->type);
+		resv_desc_ptr->type = 0;
+	}
+	if (resv_desc_ptr->partition) {
+		part_ptr = find_part_record(resv_desc_ptr->partition);
+		if (!part_ptr) {
+			info("Reservation request has invalid partition %s",
+			     resv_desc_ptr->partition);
+			rc = ESLURM_INVALID_PARTITION_NAME;
+			goto bad_parse;
+		}
+	}
+	if ((resv_desc_ptr->accounts == NULL) &&
+	    (resv_desc_ptr->users == NULL)) {
+		info("Reservation request lacks users or accounts");
+		rc = ESLURM_INVALID_BANK_ACCOUNT;
+		goto bad_parse;
+	}
+	if (resv_desc_ptr->accounts) {
+		rc = _build_account_list(resv_desc_ptr->accounts, 
+					 &account_cnt, &account_list);
+		if (rc)
+			goto bad_parse;
+	}
+	if (resv_desc_ptr->users) {
+		rc = _build_uid_list(resv_desc_ptr->users, 
+				     &user_cnt, &user_list);
+		if (rc)
+			goto bad_parse;
+	}
+	if (resv_desc_ptr->name) {
+		resv_ptr = (slurmctld_resv_t *) list_find_first (resv_list, 
+				_find_resv_name, resv_desc_ptr->name);
+		if (resv_ptr) {
+			info("Reservation requestion name duplication (%s)",
+			     resv_desc_ptr->name);
+			rc = ESLURM_RESERVATION_INVALID;
+			goto bad_parse;
+		}
+	} else {
+		while (1) {
+			_generate_resv_name(resv_desc_ptr);
+			resv_ptr = (slurmctld_resv_t *) 
+					list_find_first (resv_list, 
+					_find_resv_name, resv_desc_ptr->name);
+			if (!resv_ptr)
+				break;
+			/* Same as explicitly created name, retry */
+		}
+	}
+	if (resv_desc_ptr->node_list) {
+		if (strcmp(resv_desc_ptr->node_list, "ALL") == 0) {
+			node_bitmap = bit_alloc(node_record_count);
+			bit_nset(node_bitmap, 0, (node_record_count - 1));
+		} else if (node_name2bitmap(resv_desc_ptr->node_list, 
+					    false, &node_bitmap)) {
+			rc = ESLURM_INVALID_NODE_NAME;
+			goto bad_parse;
+		}
+		if (resv_desc_ptr->node_cnt == NO_VAL)
+			resv_desc_ptr->node_cnt = 0;
+	} else if (resv_desc_ptr->node_cnt == NO_VAL) {
+		info("Reservation request lacks node specification");
+		rc = ESLURM_INVALID_NODE_NAME;
+		goto bad_parse;
+	}
+
+	/* Create a new reservation record */
+	resv_ptr = xmalloc(sizeof(slurmctld_resv_t));
+	resv_ptr->accounts	= resv_desc_ptr->accounts;
+	resv_desc_ptr->accounts = NULL;		/* Nothing left to free */
+	resv_ptr->account_cnt	= account_cnt;
+	resv_ptr->account_list	= account_list;
+	resv_ptr->end_time	= resv_desc_ptr->end_time;
+	resv_ptr->features	= resv_desc_ptr->features;
+	resv_desc_ptr->features = NULL;		/* Nothing left to free */
+	xassert(resv_ptr->magic = RESV_MAGIC);	/* Sets value */
+	resv_ptr->name		= xstrdup(resv_desc_ptr->name);
+	resv_ptr->node_cnt	= resv_desc_ptr->node_cnt;
+	resv_ptr->node_list	= resv_desc_ptr->node_list;
+	resv_desc_ptr->node_list = NULL;	/* Nothing left to free */
+	resv_ptr->node_bitmap	= node_bitmap;	/* May be unset */
+	resv_ptr->partition	= resv_desc_ptr->partition;
+	resv_desc_ptr->partition = NULL;	/* Nothing left to free */
+	resv_ptr->part_ptr	= part_ptr;
+	resv_ptr->start_time	= resv_desc_ptr->start_time;
+	resv_ptr->type		= resv_desc_ptr->type;
+	resv_ptr->users		= resv_desc_ptr->users;
+	resv_ptr->user_cnt	= user_cnt;
+	resv_ptr->user_list	= user_list;
+	resv_desc_ptr->users 	= NULL;		/* Nothing left to free */
+	_set_resv_id(resv_ptr);
+	_set_assoc_list(resv_ptr);
+
+	info("Created reservation %s for accounts=%s users=%s",
+	     resv_ptr->name, resv_ptr->accounts, resv_ptr->users);
+	list_append(resv_list, resv_ptr);
+	last_resv_update = now;
+	schedule_resv_save();
+
+	return SLURM_SUCCESS;
+
+ bad_parse:
+	for (i=0; i<account_cnt; i++)
+		xfree(account_list[i]);
+	xfree(account_list);
+	if (node_bitmap)
+		bit_free(node_bitmap);
+	xfree(user_list);
+	return rc;
+}
+
+/* Update an exiting resource reservation */
+extern int update_resv(reserve_request_msg_t *resv_desc_ptr)
+{
+	time_t now = time(NULL);
+	slurmctld_resv_t *resv_ptr;
+	int error_code = SLURM_SUCCESS;
+
+	if (!resv_list)
+		resv_list = list_create(_del_resv_rec);
+	_dump_resv_req(resv_desc_ptr, "update_resv");
+
+	/* Find the specified reservation */
+	if ((resv_desc_ptr->name == NULL))
+		return ESLURM_RESERVATION_INVALID;
+	resv_ptr = (slurmctld_resv_t *) list_find_first (resv_list, 
+			_find_resv_name, resv_desc_ptr->name);
+	if (!resv_ptr)
+		return ESLURM_RESERVATION_INVALID;
+
+	/* Process the request */
+	last_resv_update = now;
+	if (resv_desc_ptr->start_time != (time_t) NO_VAL) {
+		if (resv_desc_ptr->start_time < (now - 60)) {
+			info("Reservation requestion has invalid start time");
+			error_code = ESLURM_INVALID_TIME_VALUE;
+			goto fini;
+		}
+		resv_ptr->start_time = resv_desc_ptr->start_time;
+	}
+	if (resv_desc_ptr->end_time != (time_t) NO_VAL) {
+		if (resv_desc_ptr->end_time < (now - 60)) {
+			info("Reservation requestion has invalid end time");
+			error_code = ESLURM_INVALID_TIME_VALUE;
+			goto fini;
+		}
+		resv_ptr->end_time = resv_desc_ptr->end_time;
+	}
+	if (resv_desc_ptr->duration != NO_VAL) {
+		resv_ptr->end_time = resv_ptr->start_time + 
+				     (resv_desc_ptr->duration * 60);
+	}
+	if (resv_desc_ptr->type != (uint16_t) NO_VAL) {
+		if (resv_desc_ptr->type > RESERVE_TYPE_MAINT) {
+			error("Invalid reservation type %u ignored",
+			      resv_desc_ptr->type);
+		} else
+			resv_ptr->type = resv_desc_ptr->type;
+	}
+	if (resv_desc_ptr->partition) {
+		struct part_record *part_ptr = NULL;
+		part_ptr = find_part_record(resv_desc_ptr->partition);
+		if (!part_ptr) {
+			info("Reservation request has invalid partition %s",
+			     resv_desc_ptr->partition);
+			error_code = ESLURM_INVALID_PARTITION_NAME;
+			goto fini;
+		}
+		resv_ptr->partition	= resv_desc_ptr->partition;
+		resv_desc_ptr->partition = NULL; /* Nothing left to free */
+		resv_ptr->part_ptr	= part_ptr;
+	}
+	if (resv_desc_ptr->node_cnt != NO_VAL)
+		resv_ptr->node_cnt = resv_desc_ptr->node_cnt;
+	if (resv_desc_ptr->accounts) {
+		int rc;
+		rc = _update_account_list(resv_ptr, resv_desc_ptr->accounts);
+		if (rc) {
+			error_code = rc;
+			goto fini;
+		}
+	}
+	if (resv_desc_ptr->features) {
+		xfree(resv_ptr->features);
+		resv_ptr->features = resv_desc_ptr->features;
+		resv_desc_ptr->features = NULL;	/* Nothing left to free */
+	}
+	if (resv_desc_ptr->users) {
+		int rc;
+		rc = _update_uid_list(resv_ptr, 
+				      resv_desc_ptr->users);
+		if (rc) {
+			error_code = rc;
+			goto fini;
+		}
+	}
+	if (resv_desc_ptr->node_list) {		/* Change bitmap last */
+		bitstr_t *node_bitmap;
+		if (strcmp(resv_desc_ptr->node_list, "ALL") == 0) {
+			node_bitmap = bit_alloc(node_record_count);
+			bit_nset(node_bitmap, 0, (node_record_count - 1));
+		} else if (node_name2bitmap(resv_desc_ptr->node_list, 
+					    false, &node_bitmap)) {
+			error_code = ESLURM_INVALID_NODE_NAME;
+			goto fini;
+		}
+		xfree(resv_ptr->node_list);
+		resv_ptr->node_list = resv_desc_ptr->node_list;
+		resv_desc_ptr->node_list = NULL;  /* Nothing left to free */
+		FREE_NULL_BITMAP(resv_ptr->node_bitmap);
+		resv_ptr->node_bitmap = node_bitmap;
+	}
+
+fini:	last_resv_update = now;
+	_set_assoc_list(resv_ptr);
+	_updated_resv(resv_ptr);
+	schedule_resv_save();
+	return error_code;
+}
+
+/* Delete an exiting resource reservation */
+extern int delete_resv(reservation_name_msg_t *resv_desc_ptr)
+{
+	ListIterator iter;
+	slurmctld_resv_t *resv_ptr;
+
+#ifdef _RESV_DEBUG
+	info("delete_resv: Name=%s", resv_desc_ptr->name);
+#endif
+
+	iter = list_iterator_create(resv_list);
+	if (!iter)
+		fatal("malloc: list_iterator_create");
+	while ((resv_ptr = (slurmctld_resv_t *) list_next(iter))) {
+		if (strcmp(resv_ptr->name, resv_desc_ptr->name))
+			continue;
+		_deleted_resv(resv_ptr);
+		list_delete_item(iter);
+		last_resv_update = time(NULL);
+		break;
+	}
+	list_iterator_destroy(iter);
+
+	if (!resv_ptr) {
+		info("Reservation %s not found for deletion",
+		     resv_desc_ptr->name);
+		return ESLURM_RESERVATION_INVALID;
+	}
+
+	schedule_resv_save();
+	return SLURM_SUCCESS;
+}
+
+/* Dump the reservation records to a buffer */
+extern void show_resv(char **buffer_ptr, int *buffer_size, uid_t uid)
+{
+	ListIterator iter;
+	slurmctld_resv_t *resv_ptr;
+	uint32_t resv_packed;
+	int tmp_offset;
+	Buf buffer;
+	time_t now = time(NULL);
+	DEF_TIMERS;
+
+	START_TIMER;
+	if (!resv_list)
+		resv_list = list_create(_del_resv_rec);
+
+	buffer_ptr[0] = NULL;
+	*buffer_size = 0;
+
+	buffer = init_buf(BUF_SIZE);
+
+	/* write header: version and time */
+	resv_packed = 0;
+	pack32(resv_packed, buffer);
+	pack_time(now, buffer);
+
+	/* write individual reservation records */
+	iter = list_iterator_create(resv_list);
+	if (!iter)
+		fatal("malloc: list_iterator_create");
+	while ((resv_ptr = (slurmctld_resv_t *) list_next(iter))) {
+		_pack_resv(resv_ptr, buffer, false);
+		resv_packed++;
+	}
+	list_iterator_destroy(iter);
+
+	/* put the real record count in the message body header */
+	tmp_offset = get_buf_offset(buffer);
+	set_buf_offset(buffer, 0);
+	pack32(resv_packed, buffer);
+	set_buf_offset(buffer, tmp_offset);
+
+	*buffer_size = get_buf_offset(buffer);
+	buffer_ptr[0] = xfer_buf_data(buffer);
+	END_TIMER2("show_resv");
+}
+
+/* Save the state of all reservations to file */
+extern int dump_all_resv_state(void)
+{
+	ListIterator iter;
+	slurmctld_resv_t *resv_ptr;
+	int error_code = 0, log_fd;
+	char *old_file, *new_file, *reg_file;
+	/* Locks: Read node */
+	slurmctld_lock_t resv_read_lock =
+	    { READ_LOCK, NO_LOCK, READ_LOCK, NO_LOCK };
+	Buf buffer = init_buf(BUF_SIZE);
+	time_t now = time(NULL);
+	DEF_TIMERS;
+
+	START_TIMER;
+	if (!resv_list)
+		resv_list = list_create(_del_resv_rec);
+
+	/* write header: time */
+	packstr(RESV_STATE_VERSION, buffer);
+	pack_time(time(NULL), buffer);
+	pack32(top_suffix, buffer);
+
+	/* write reservation records to buffer */
+	lock_slurmctld(resv_read_lock);
+	iter = list_iterator_create(resv_list);
+	if (!iter)
+		fatal("malloc: list_iterator_create");
+	while ((resv_ptr = (slurmctld_resv_t *) list_next(iter))) {
+		if (resv_ptr->end_time > now) {
+			_pack_resv(resv_ptr, buffer, true);
+		} else {
+			debug("Purging vestigial reservation record %s",
+			      resv_ptr->name);
+			list_delete_item(iter);
+		}
+	}
+	list_iterator_destroy(iter);
+	/* Maintain config read lock until we copy state_save_location *\
+	\* unlock_slurmctld(resv_read_lock);          - see below      */
+
+	/* write the buffer to file */
+	old_file = xstrdup(slurmctld_conf.state_save_location);
+	xstrcat(old_file, "/resv_state.old");
+	reg_file = xstrdup(slurmctld_conf.state_save_location);
+	xstrcat(reg_file, "/resv_state");
+	new_file = xstrdup(slurmctld_conf.state_save_location);
+	xstrcat(new_file, "/resv_state.new");
+	unlock_slurmctld(resv_read_lock);
+	lock_state_files();
+	log_fd = creat(new_file, 0600);
+	if (log_fd == 0) {
+		error("Can't save state, error creating file %s, %m",
+		      new_file);
+		error_code = errno;
+	} else {
+		int pos = 0, nwrite = get_buf_offset(buffer), amount;
+		char *data = (char *)get_buf_data(buffer);
+
+		while (nwrite > 0) {
+			amount = write(log_fd, &data[pos], nwrite);
+			if ((amount < 0) && (errno != EINTR)) {
+				error("Error writing file %s, %m", new_file);
+				error_code = errno;
+				break;
+			}
+			nwrite -= amount;
+			pos    += amount;
+		}
+		fsync(log_fd);
+		close(log_fd);
+	}
+	if (error_code)
+		(void) unlink(new_file);
+	else {			/* file shuffle */
+		(void) unlink(old_file);
+		(void) link(reg_file, old_file);
+		(void) unlink(reg_file);
+		(void) link(new_file, reg_file);
+		(void) unlink(new_file);
+	}
+	xfree(old_file);
+	xfree(reg_file);
+	xfree(new_file);
+	unlock_state_files();
+
+	free_buf(buffer);
+	END_TIMER2("dump_all_resv_state");
+	return 0;
+}
+
+/* Validate one reservation record, return true if good */
+static bool _validate_one_reservation(slurmctld_resv_t *resv_ptr)
+{
+	if ((resv_ptr->name == NULL) || (resv_ptr->name[0] == '\0')) {
+		error("Read reservation without name");
+		return false;
+	}
+	if (resv_ptr->type > RESERVE_TYPE_MAINT) {
+		error("Reservation %s has invalid type (%u)",
+		      resv_ptr->name, resv_ptr->type);
+		return false;
+	}
+	if (resv_ptr->partition) {
+		struct part_record *part_ptr = NULL;
+		part_ptr = find_part_record(resv_ptr->partition);
+		if (!part_ptr) {
+			error("Reservation %s has invalid partition (%s)",
+			      resv_ptr->name, resv_ptr->partition);
+			return false;
+		}
+		resv_ptr->part_ptr	= part_ptr;
+	}
+	if (resv_ptr->accounts) {
+		int account_cnt = 0, i, rc;
+		char **account_list;
+		rc = _build_account_list(resv_ptr->accounts, 
+					 &account_cnt, &account_list);
+		if (rc) {
+			error("Reservation %s has invalid accounts (%s)",
+			      resv_ptr->name, resv_ptr->accounts);
+			return false;
+		}
+		for (i=0; i<resv_ptr->account_cnt; i++)
+			xfree(resv_ptr->account_list[i]);
+		xfree(resv_ptr->account_list);
+		resv_ptr->account_cnt  = account_cnt;
+		resv_ptr->account_list = account_list;
+	}
+	if (resv_ptr->users) {
+		int rc, user_cnt = 0;
+		uid_t *user_list = NULL;
+		rc = _build_uid_list(resv_ptr->users, 
+				     &user_cnt, &user_list);
+		if (rc) {
+			error("Reservation %s has invalid users (%s)",
+			      resv_ptr->name, resv_ptr->users);
+			return false;
+		}
+		xfree(resv_ptr->user_list);
+		resv_ptr->user_cnt  = user_cnt;
+		resv_ptr->user_list = user_list;
+	}
+	if (resv_ptr->node_list) {		/* Change bitmap last */
+		bitstr_t *node_bitmap;
+		if (strcmp(resv_ptr->node_list, "ALL") == 0) {
+			node_bitmap = bit_alloc(node_record_count);
+			bit_nset(node_bitmap, 0, (node_record_count - 1));
+		} else if (node_name2bitmap(resv_ptr->node_list, 
+					    false, &node_bitmap)) {
+			error("Reservation %s has invalid nodes (%s)",
+			      resv_ptr->name, resv_ptr->node_list);
+			return false;
+		}
+		FREE_NULL_BITMAP(resv_ptr->node_bitmap);
+		resv_ptr->node_bitmap = node_bitmap;
+	}
+	return true;
+}
+
+/*
+ * Validate all reservation records, reset bitmaps, etc.
+ * Purge any invalid reservation.
+ */
+static void _validate_all_reservations(void)
+{
+	ListIterator iter;
+	slurmctld_resv_t *resv_ptr;
+	time_t now = time(NULL);
+	char *tmp;
+	uint32_t res_num;
+
+	iter = list_iterator_create(resv_list);
+	if (!iter)
+		fatal("malloc: list_iterator_create");
+	while ((resv_ptr = (slurmctld_resv_t *) list_next(iter))) {
+		if (resv_ptr->end_time < now) {
+			debug("Purging vestigial reservation record %s",
+			      resv_ptr->name);
+			list_delete_item(iter);
+		} else if (!_validate_one_reservation(resv_ptr)) {
+			error("Purging invalid reservation record %s",
+			      resv_ptr->name);
+			list_delete_item(iter);
+		} else {
+			_set_assoc_list(resv_ptr);
+			tmp = strrchr(resv_ptr->name, '_');
+			if (tmp) {
+				res_num = atoi(tmp + 1);
+				top_suffix = MAX(top_suffix, res_num);
+			}
+		}
+	}
+	list_iterator_destroy(iter);
+}
+
+/*
+ * Load the reservation state from file, recover on slurmctld restart. 
+ *	execute this after loading the configuration file data.
+ * IN recover - 0 = no change
+ *              1 = validate existing (in memory) reservations
+ *              2 = recover all reservation state from disk
+ * RET SLURM_SUCCESS or error code
+ * NOTE: READ lock_slurmctld config before entry
+ */
+extern int load_all_resv_state(int recover)
+{
+	char *state_file, *data = NULL, *ver_str = NULL;
+	time_t now;
+	uint32_t data_size = 0, uint32_tmp;
+	int data_allocated, data_read = 0, error_code = 0, state_fd;
+	Buf buffer;
+	slurmctld_resv_t *resv_ptr = NULL;
+
+	last_resv_update = time(NULL);
+	if (recover == 0) {
+		if (resv_list)
+			_validate_all_reservations();
+		else
+			resv_list = list_create(_del_resv_rec);
+		return SLURM_SUCCESS;
+	}
+
+	if (resv_list)
+		list_flush(resv_list);
+	else
+		resv_list = list_create(_del_resv_rec);
+
+	/* read the file */
+	state_file = xstrdup(slurmctld_conf.state_save_location);
+	xstrcat(state_file, "/resv_state");
+	lock_state_files();
+	state_fd = open(state_file, O_RDONLY);
+	if (state_fd < 0) {
+		info("No reservation state file (%s) to recover",
+		     state_file);
+		error_code = ENOENT;
+	} else {
+		data_allocated = BUF_SIZE;
+		data = xmalloc(data_allocated);
+		while (1) {
+			data_read = read(state_fd, &data[data_size], 
+					BUF_SIZE);
+			if (data_read < 0) {
+				if  (errno == EINTR)
+					continue;
+				else {
+					error("Read error on %s: %m", 
+						state_file);
+					break;
+				}
+			} else if (data_read == 0)     /* eof */
+				break;
+			data_size      += data_read;
+			data_allocated += data_read;
+			xrealloc(data, data_allocated);
+		}
+		close(state_fd);
+	}
+	xfree(state_file);
+	unlock_state_files();
+
+	buffer = create_buf(data, data_size);
+
+	safe_unpackstr_xmalloc( &ver_str, &uint32_tmp, buffer);
+	debug3("Version string in resv_state header is %s", ver_str);
+	if ((!ver_str) || (strcmp(ver_str, RESV_STATE_VERSION) != 0)) {
+		error("************************************************************");
+		error("Can not recover reservation state, data version incompatable");
+		error("************************************************************");
+		xfree(ver_str);
+		free_buf(buffer);
+		return EFAULT;
+	}
+	xfree(ver_str);
+	safe_unpack_time(&now, buffer);
+	safe_unpack32(&top_suffix, buffer);
+
+	while (remaining_buf(buffer) > 0) {
+		resv_ptr = xmalloc(sizeof(slurmctld_resv_t));
+		xassert(resv_ptr->magic = RESV_MAGIC);	/* Sets value */
+		safe_unpackstr_xmalloc(&resv_ptr->accounts,	
+				       &uint32_tmp,	buffer);
+		safe_unpack_time(&resv_ptr->end_time,	buffer);
+		safe_unpackstr_xmalloc(&resv_ptr->features,
+				       &uint32_tmp, 	buffer);
+		safe_unpackstr_xmalloc(&resv_ptr->name,	&uint32_tmp, buffer);
+		safe_unpack32(&resv_ptr->node_cnt,	buffer);
+		safe_unpackstr_xmalloc(&resv_ptr->node_list,
+				       &uint32_tmp,	buffer);
+		safe_unpackstr_xmalloc(&resv_ptr->partition,
+				       &uint32_tmp, 	buffer);
+		safe_unpack_time(&resv_ptr->start_time,	buffer);
+		safe_unpack16(&resv_ptr->type,		buffer);
+		safe_unpackstr_xmalloc(&resv_ptr->users,&uint32_tmp, buffer);
+
+		/* Fields saved for internal use only (save state) */
+		safe_unpackstr_xmalloc(&resv_ptr->assoc_list,	
+				       &uint32_tmp,	buffer);
+		safe_unpack32(&resv_ptr->cpu_cnt,	buffer);
+		safe_unpack32(&resv_ptr->resv_id,	buffer);
+
+		list_append(resv_list, resv_ptr);
+		info("Recovered state of reservation %s", resv_ptr->name);
+	}
+
+	_validate_all_reservations();
+	info("Recovered state of %d reservations", list_count(resv_list));
+	free_buf(buffer);
+	return error_code;
+
+      unpack_error:
+	_validate_all_reservations();
+	error("Incomplete reservation data checkpoint file");
+	info("Recovered state of %d reservations", list_count(resv_list));
+	if (resv_ptr)
+		_del_resv_rec(resv_ptr);
+	free_buf(buffer);
+	return EFAULT;
+}
diff --git a/src/slurmctld/reservation.h b/src/slurmctld/reservation.h
index ae173b82449..2ae54e56a98 100644
--- a/src/slurmctld/reservation.h
+++ b/src/slurmctld/reservation.h
@@ -15,7 +15,7 @@
  *  any later version.
  *
  *  In addition, as a special exception, the copyright holders give permission 
- *  to link the code of portions of this program with the OpenSSL library under 
+ *  to link the code of portions of this program with the OpenSSL library under
  *  certain conditions as described in each individual source file, and 
  *  distribute linked combinations including the two. You must obey the GNU 
  *  General Public License in all respects for all of the code used other than 
@@ -38,4 +38,36 @@
 #ifndef _RESERVATION_H
 #define _RESERVATION_H
 
+#include <time.h>
+#include <unistd.h>
+#include <slurm/slurm.h>
+
+extern time_t last_resv_update;
+
+/* Create a resource reservation */
+extern int create_resv(reserve_request_msg_t *resv_desc_ptr);
+
+/* Update an exiting resource reservation */
+extern int update_resv(reserve_request_msg_t *resv_desc_ptr);
+
+/* Delete an exiting resource reservation */
+extern int delete_resv(reservation_name_msg_t *resv_desc_ptr);
+
+/* Dump the reservation records to a buffer */
+extern void show_resv(char **buffer_ptr, int *buffer_size, uid_t uid);
+
+/* Save the state of all reservations to file */
+extern int dump_all_resv_state(void);
+
+/*
+ * Load the reservation state from file, recover on slurmctld restart. 
+ *	execute this after loading the configuration file data.
+ * IN recover - 0 = no change
+ *              1 = validate existing (in memory) reservations
+ *              2 = recover all reservation state from disk
+ * RET SLURM_SUCCESS or error code
+ * NOTE: READ lock_slurmctld config before entry
+ */
+extern int load_all_resv_state(int recover);
+
 #endif /* !_RESERVATION_H */
diff --git a/src/slurmctld/slurmctld.h b/src/slurmctld/slurmctld.h
index a7cb55d14bd..b20d729d9d6 100644
--- a/src/slurmctld/slurmctld.h
+++ b/src/slurmctld/slurmctld.h
@@ -2,7 +2,7 @@
  *  slurmctld.h - definitions of functions and structures for slurmcltd use
  *****************************************************************************
  *  Copyright (C) 2002-2007 The Regents of the University of California.
- *  Copyright (C) 2008 Lawrence Livermore National Security.
+ *  Copyright (C) 2008-2009 Lawrence Livermore National Security.
  *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
  *  Written by Morris Jette <jette1@llnl.gov> et. al.
  *  LLNL-CODE-402394.
diff --git a/src/slurmctld/state_save.c b/src/slurmctld/state_save.c
index 105b624bfd8..23bc77c1044 100644
--- a/src/slurmctld/state_save.c
+++ b/src/slurmctld/state_save.c
@@ -2,6 +2,7 @@
  *  state_save.c - Keep saved slurmctld state current 
  *****************************************************************************
  *  Copyright (C) 2004-2007 The Regents of the University of California.
+ *  Copyright (C) 2008-2009 Lawrence Livermore National Security.
  *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
  *  Written by Morris Jette <jette1@llnl.gov>
  *  LLNL-CODE-402394.
@@ -44,12 +45,14 @@
 #endif                          /* WITH_PTHREADS */
 
 #include "src/common/macros.h"
+#include "src/slurmctld/reservation.h"
 #include "src/slurmctld/slurmctld.h"
 #include "src/slurmctld/trigger_mgr.h"
 
 static pthread_mutex_t state_save_lock = PTHREAD_MUTEX_INITIALIZER;
 static pthread_cond_t  state_save_cond = PTHREAD_COND_INITIALIZER;
-static int save_jobs = 0, save_nodes = 0, save_parts = 0, save_triggers = 0;
+static int save_jobs = 0, save_nodes = 0, save_parts = 0;
+static int save_triggers = 0, save_resv = 0;
 static bool run_save_thread = true;
 
 /* Queue saving of job state information */
@@ -79,6 +82,15 @@ extern void schedule_part_save(void)
 	pthread_cond_broadcast(&state_save_cond);
 }
 
+/* Queue saving of reservation state information */
+extern void schedule_resv_save(void)
+{
+	slurm_mutex_lock(&state_save_lock);
+	save_resv++;
+	slurm_mutex_unlock(&state_save_lock);
+	pthread_cond_broadcast(&state_save_cond);
+}
+
 /* Queue saving of trigger state information */
 extern void schedule_trigger_save(void)
 {
@@ -113,7 +125,7 @@ extern void *slurmctld_state_save(void *no_data)
 		slurm_mutex_lock(&state_save_lock);
 		while (1) {
 			if (save_jobs + save_nodes + save_parts + 
-			    save_triggers)
+			    save_resv + save_triggers)
 				break;		/* do the work */
 			else if (!run_save_thread) {
 				run_save_thread = true;
@@ -157,6 +169,17 @@ extern void *slurmctld_state_save(void *no_data)
 		if (run_save)
 			(void)dump_all_part_state();
 
+		/* save reservation info if necessary */
+		run_save = false;
+		slurm_mutex_lock(&state_save_lock);
+		if (save_resv) {
+			run_save = true;
+			save_resv = 0;
+		}
+		slurm_mutex_unlock(&state_save_lock);
+		if (run_save)
+			(void)dump_all_resv_state();
+
 		/* save trigger info if necessary */
 		run_save = false;
 		slurm_mutex_lock(&state_save_lock);
diff --git a/src/slurmctld/state_save.h b/src/slurmctld/state_save.h
index d800752ad16..181b58747b0 100644
--- a/src/slurmctld/state_save.h
+++ b/src/slurmctld/state_save.h
@@ -2,6 +2,7 @@
  *  state_save.h - Definitions for keeping saved slurmctld state current 
  *****************************************************************************
  *  Copyright (C) 2004-2007 The Regents of the University of California.
+ *  Copyright (C) 2008-2009 Lawrence Livermore National Security.
  *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
  *  Written by Morris Jette <jette1@llnl.gov>
  *  LLNL-CODE-402394.
@@ -15,7 +16,7 @@
  *  any later version.
  *
  *  In addition, as a special exception, the copyright holders give permission 
- *  to link the code of portions of this program with the OpenSSL library under 
+ *  to link the code of portions of this program with the OpenSSL library under
  *  certain conditions as described in each individual source file, and 
  *  distribute linked combinations including the two. You must obey the GNU 
  *  General Public License in all respects for all of the code used other than 
@@ -47,6 +48,9 @@ extern void schedule_node_save(void);
 /* Queue saving of partition state information */
 extern void schedule_part_save(void);
 
+/* Queue saving of reservation state information */
+extern void schedule_resv_save(void);
+
 /* Queue saving of trigger state information */
 extern void schedule_trigger_save(void);
 
-- 
GitLab