diff --git a/slurm/slurm.h.in b/slurm/slurm.h.in
index af730d04165e95749da6ac2c2e07be8e04805ee3..3f98e4aa9c08039fd1fdf163e57fcea2b9cc1c05 100644
--- a/slurm/slurm.h.in
+++ b/slurm/slurm.h.in
@@ -226,6 +226,7 @@ enum job_state_reason {
 	WAIT_ASSOC_JOB_LIMIT,	/* user/bank job limit reached */
 	WAIT_ASSOC_RESOURCE_LIMIT,/* user/bank resource limit reached */
 	WAIT_ASSOC_TIME_LIMIT,  /* user/bank time limit reached */
+	WAIT_RESERVATION,	/* reservation not available */
 	WAIT_TBD1,
 	WAIT_TBD2,
 	FAIL_DOWN_PARTITION,	/* partition for job is DOWN */
diff --git a/slurm/slurm_errno.h b/slurm/slurm_errno.h
index 1f4afbc2fb2931b0912ed791805d125a61eb0d54..e1b138306b4c7cbd8d27a60e3756d30fcb5726be 100644
--- a/slurm/slurm_errno.h
+++ b/slurm/slurm_errno.h
@@ -164,6 +164,7 @@ enum {
 	ESLURM_RESERVATION_INVALID,
 	ESLURM_INVALID_TIME_VALUE,
 	ESLURM_RESERVATION_BUSY,
+	ESLURM_RESERVATION_NOT_USABLE,
 
 	/* switch specific error codes, specific values defined in plugin module */
 	ESLURM_SWITCH_MIN = 3000,
diff --git a/src/common/node_select.c b/src/common/node_select.c
index 02720cf7dcc9db64d66b00083f729dba13b4ce9a..964f8439b7f1f4dd99c25c4bb22759bf0cf2ba5d 100644
--- a/src/common/node_select.c
+++ b/src/common/node_select.c
@@ -1728,6 +1728,7 @@ extern char *select_g_sprint_jobinfo(select_jobinfo_t jobinfo,
 		snprintf(buf, size, "%s", jobinfo->reservation_id);
 		break;	
 	default:
+		/* likely a BlueGene specific mode */
 		error("select_g_sprint_jobinfo: bad mode %d", mode);
 		if (size > 0)
 			buf[0] = '\0';
diff --git a/src/common/slurm_errno.c b/src/common/slurm_errno.c
index ec7030324875dafdc1f57a14cd66fc6605b7dc35..2f966f0d32421e9a2ba82658ea581836f5a9d599 100644
--- a/src/common/slurm_errno.c
+++ b/src/common/slurm_errno.c
@@ -229,7 +229,9 @@ static slurm_errtab_t slurm_errtab[] = {
 	{ ESLURM_INVALID_TIME_VALUE,
 	  "Invalid time specified"				},
 	{ ESLURM_RESERVATION_BUSY, 
-	  "Requested reservation is busy"			},
+	  "Requested reservation is in use"			},
+	{ ESLURM_RESERVATION_NOT_USABLE, 
+	  "Requested reservation not usable now"		},
 
 	/* slurmd error codes */
 
diff --git a/src/common/slurm_protocol_defs.c b/src/common/slurm_protocol_defs.c
index cfa75da62766bca56c2547f7f6e89d858b3a463c..bdc59128d1c917ebb2adc6a915c1805995e7176a 100644
--- a/src/common/slurm_protocol_defs.c
+++ b/src/common/slurm_protocol_defs.c
@@ -739,6 +739,8 @@ extern char *job_reason_string(enum job_state_reason inx)
 			return "AssociationResourceLimit";
 		case WAIT_ASSOC_TIME_LIMIT:
 			return "AssociationTimeLimit";
+		case WAIT_RESERVATION:
+			return "Reservation";
 		case FAIL_DOWN_PARTITION:
 			return "PartitionDown";
 		case FAIL_DOWN_NODE:
diff --git a/src/slurmctld/reservation.c b/src/slurmctld/reservation.c
index f0a97ff3bc1460a62c8fcfced10693cf144cd920..7c2eefcd4a0e887768c0a6503f621684e79a7bb3 100644
--- a/src/slurmctld/reservation.c
+++ b/src/slurmctld/reservation.c
@@ -75,8 +75,6 @@
 /* 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	*/
@@ -100,6 +98,8 @@ typedef struct slurmctld_resv {
 	uid_t *user_list;	/* array of users permitted to use	*/
 } slurmctld_resv_t;
 
+time_t last_resv_update = (time_t) 0;
+
 List     resv_list = (List) NULL;
 uint32_t top_suffix = 0;
 
@@ -126,6 +126,8 @@ static int  _update_account_list(struct slurmctld_resv *resv_ptr,
 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 int  _valid_job_access_resv(struct job_record *job_ptr,
+				   slurmctld_resv_t *resv_ptr);
 static bool _validate_one_reservation(slurmctld_resv_t *resv_ptr);
 
 
@@ -136,6 +138,7 @@ static void _del_resv_rec(void *x)
 
 	if (resv_ptr) {
 		xassert(resv_ptr->magic == RESV_MAGIC);
+		resv_ptr->magic = 0;
 		xfree(resv_ptr->accounts);
 		for (i=0; i<resv_ptr->account_cnt; i++)
 			xfree(resv_ptr->account_list[i]);
@@ -1446,14 +1449,14 @@ extern int load_all_resv_state(int recover)
 }
 
 /*
- * Validate a job request with respect to reservations
+ * Determine if a job request can use the specified reservations
  * IN/OUT job_ptr - job to validate, set its resv_id and resv_type
  * RET SLURM_SUCCESS or error code (not found or access denied)
 */
 extern int validate_job_resv(struct job_record *job_ptr)
 {
 	slurmctld_resv_t *resv_ptr = NULL;
-	int i;
+	int rc;
 
 	xassert(job_ptr);
 
@@ -1475,30 +1478,116 @@ extern int validate_job_resv(struct job_record *job_ptr)
 		return ESLURM_RESERVATION_INVALID;
 	}
 
+	rc = _valid_job_access_resv(job_ptr, resv_ptr);
+	if (rc == SLURM_SUCCESS) {
+		job_ptr->resv_id   = resv_ptr->resv_id;
+		job_ptr->resv_type = resv_ptr->type;
+	}
+	return rc;
+}
+
+/* Determine if a job has access to a reservation
+ * RET SLURM_SUCCESS if true, ESLURM_RESERVATION_ACCESS otherwise */
+static int _valid_job_access_resv(struct job_record *job_ptr,
+				  slurmctld_resv_t *resv_ptr)
+{
+	int i;
+
 	/* Determine if we have access */
 	if (/*association_enforced*/ 0) {
 		/* FIXME: add association checks
 		if (job_ptr->assoc_id in reservation association list)
-			goto allow;
+			return SLURM_SUCCESS;
 		*/
 	} else {
 		for (i=0; i<resv_ptr->user_cnt; i++) {
 			if (job_ptr->user_id == resv_ptr->user_list[i])
-				goto allow;
+				return SLURM_SUCCESS;
 		}
 		for (i=0; (i<resv_ptr->account_cnt) && job_ptr->account; i++) {
 			if (resv_ptr->account_list[i] &&
 			    (strcmp(job_ptr->account, 
 				    resv_ptr->account_list[i]) == 0)) {
-				goto allow;
+				return SLURM_SUCCESS;
 			}
 		}
 	}
-	error("Security violation, uid=%u attempt to use reservation %s",
-	      job_ptr->user_id, resv_ptr->name);
-	return ESLURM_ACCESS_DENIED;
+	info("Security violation, uid=%u attempt to use reservation %s",
+	     job_ptr->user_id, resv_ptr->name);
+	return ESLURM_RESERVATION_ACCESS;
+}
+
+/*
+ * Determine which nodes a job can use based upon reservations
+ * IN job_ptr      - job to test
+ * IN/OUT when     - when we want the job to start (IN)
+ *                   when the reservation is available (OUT)
+ * OUT node_bitmap - nodes which the job can use, caller must free unless error
+ * RET	SLURM_SUCCESS if runable now
+ *	ESLURM_RESERVATION_ACCESS access to reservation denied
+ *	ESLURM_RESERVATION_INVALID reservation invalid
+ *	ESLURM_INVALID_TIME_VALUE reservation invalid at time "when"
+ */
+extern int job_test_resv(struct job_record *job_ptr, time_t *when,
+			 bitstr_t **node_bitmap)
+{
+	slurmctld_resv_t * resv_ptr;
+	time_t job_start_time, job_end_time;
+	ListIterator iter;
+
+	*node_bitmap = (bitstr_t *) NULL;
+
+	if (job_ptr->resv_name) {
+		resv_ptr = (slurmctld_resv_t *) list_find_first (resv_list, 
+				_find_resv_name, job_ptr->resv_name);
+		if (!resv_ptr)
+			return ESLURM_RESERVATION_INVALID;
+		if (_valid_job_access_resv(job_ptr, resv_ptr) != SLURM_SUCCESS)
+			return ESLURM_RESERVATION_ACCESS;
+		if (*when < resv_ptr->start_time) {
+			/* reservation starts later */
+			*when = resv_ptr->start_time;
+			return ESLURM_INVALID_TIME_VALUE;
+		}
+		if (*when > resv_ptr->end_time) {
+			/* reservation ended earlier */
+			*when = resv_ptr->end_time;
+			job_ptr->priority = 0;	/* administrative hold */
+			return ESLURM_INVALID_TIME_VALUE;
+		}
+		*node_bitmap = bit_copy(resv_ptr->node_bitmap);
+		return SLURM_SUCCESS;
+	}
+
+	*node_bitmap = bit_copy(avail_node_bitmap);
+	if (list_count(resv_list) == 0)
+		return SLURM_SUCCESS;
+
+	job_start_time = job_end_time = *when;
+	if (job_ptr->time_limit == INFINITE)
+		job_end_time += 365 * 24 * 60 * 60;
+	else if (job_ptr->time_limit != NO_VAL)
+		job_end_time += (job_ptr->time_limit * 60);
+	else {	/* partition time limit */
+		if (job_ptr->part_ptr->max_time == INFINITE)
+			job_end_time += 365 * 24 * 60 * 60;
+		else
+			job_end_time += (job_ptr->part_ptr->max_time * 60);
+	}
+
+	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->node_bitmap == NULL) ||
+		    (resv_ptr->start_time > job_end_time) ||
+		    (resv_ptr->end_time   < job_start_time))
+			continue;
+		bit_not(resv_ptr->node_bitmap);
+		bit_and(*node_bitmap, resv_ptr->node_bitmap);
+		bit_not(resv_ptr->node_bitmap);
+	}
+	list_iterator_destroy(iter);
 
- allow:	job_ptr->resv_id   = resv_ptr->resv_id;
-	job_ptr->resv_type = resv_ptr->type;
 	return SLURM_SUCCESS;
 }
diff --git a/src/slurmctld/reservation.h b/src/slurmctld/reservation.h
index aeed51cc213261c49c8c8ed99330707ba633ec62..a01b423b4b3d30344fbce204653727a0b116301d 100644
--- a/src/slurmctld/reservation.h
+++ b/src/slurmctld/reservation.h
@@ -41,6 +41,7 @@
 #include <time.h>
 #include <unistd.h>
 #include <slurm/slurm.h>
+#include "src/common/bitstring.h"
 #include "src/slurmctld/slurmctld.h"
 
 extern time_t last_resv_update;
@@ -72,10 +73,24 @@ extern int dump_all_resv_state(void);
 extern int load_all_resv_state(int recover);
 
 /*
- * Validate a job request with respect to reservations
+ * Determine if a job request can use the specified reservations
  * IN/OUT job_ptr - job to validate, set its resv_id and resv_type
  * RET SLURM_SUCCESS or error code (not found or access denied)
 */
 extern int validate_job_resv(struct job_record *job_ptr);
 
+/*
+ * Determine which nodes a job can use based upon reservations
+ * IN job_ptr      - job to test
+ * IN/OUT when     - when we want the job to start (IN)
+ *                   when the reservation is available (OUT)
+ * OUT node_bitmap - nodes which the job can use, caller must free
+ * RET	SLURM_SUCCESS if runable now
+ *	ESLURM_RESERVATION_ACCESS access to reservation denied
+ *	ESLURM_RESERVATION_INVALID reservation invalid
+ *	ESLURM_INVALID_TIME_VALUE reservation invalid at time "when"
+ */
+extern int job_test_resv(struct job_record *job_ptr, time_t *when,
+			 bitstr_t **node_bitmap);
+
 #endif /* !_RESERVATION_H */