From a695b8e40e56f3c7d2e7bab1a5bf2015f81dac21 Mon Sep 17 00:00:00 2001
From: Danny Auble <da@llnl.gov>
Date: Tue, 7 Oct 2008 21:21:53 +0000
Subject: [PATCH] svn merge -r15330:15339
 https://eris.llnl.gov/svn/slurm/branches/slurm-1.3

---
 NEWS                                          |  3 +
 auxdir/x_ac_debug.m4                          | 21 ++++-
 configure                                     | 74 ++++++++++++-----
 doc/html/accounting.shtml                     |  7 +-
 doc/html/faq.shtml                            | 32 ++-----
 doc/html/programmer_guide.shtml               |  7 +-
 doc/html/sched_policy.shtml                   |  9 +-
 src/common/assoc_mgr.c                        |  1 +
 src/common/slurm_accounting_storage.c         | 28 +++++--
 .../mysql/accounting_storage_mysql.c          | 19 +++--
 src/sacctmgr/account_functions.c              |  5 ++
 src/sacctmgr/cluster_functions.c              |  1 +
 src/sacctmgr/common.c                         | 83 +++++++++++++++++--
 src/sacctmgr/file_functions.c                 |  1 +
 src/sacctmgr/user_functions.c                 | 12 +--
 src/slurmctld/job_mgr.c                       | 25 +++---
 src/slurmctld/proc_req.c                      |  5 +-
 17 files changed, 242 insertions(+), 91 deletions(-)

diff --git a/NEWS b/NEWS
index dbe0ed67d36..77732b35107 100644
--- a/NEWS
+++ b/NEWS
@@ -132,6 +132,9 @@ documents those changes that are of interest to users and admins.
     avoid trash in the accounting system.  If the users default account 
     does not have an association on the cluster the requested account 
     will be used.
+ -- Add configuration parameter "--have-front-end" to define HAVE_FRONT_END 
+    in config.h and run slurmd only on a front end (suitable only for SLURM
+    development and testing).
 
 * Changes in SLURM 1.3.8
 ========================
diff --git a/auxdir/x_ac_debug.m4 b/auxdir/x_ac_debug.m4
index 7882349ccbf..5f6dfb1526f 100644
--- a/auxdir/x_ac_debug.m4
+++ b/auxdir/x_ac_debug.m4
@@ -8,8 +8,8 @@
 #    X_AC_DEBUG
 #
 #  DESCRIPTION:
-#    Add support for the "--enable-debug" and "--enable-memory-leak-debug"
-#    configure script options.
+#    Add support for the "--enable-debug", "--enable-memory-leak-debug",
+#    and "--enable-front-end" configure script options.
 #    If debugging is enabled, CFLAGS will be prepended with the debug flags.
 #    The NDEBUG macro (used by assert) will also be set accordingly.
 #
@@ -56,5 +56,22 @@ AC_DEFUN([X_AC_DEBUG], [
   fi
   AC_MSG_RESULT([${x_ac_memory_debug=no}])
 
+  AC_MSG_CHECKING([whether to enable slurmd operation on a front-end])
+  AC_ARG_ENABLE(
+    [front-end],
+     AS_HELP_STRING(--enable-front-end, enable slurmd operation on a front-end),
+     [ case "$enableval" in
+        yes) x_ac_front_end=yes ;;
+         no) x_ac_front_end=no ;;
+          *) AC_MSG_RESULT([doh!])
+             AC_MSG_ERROR([bad value "$enableval" for --enable-front-end]) ;;
+      esac
+    ]
+  )
+  if test "$x_ac_front_end" = yes; then
+    AC_DEFINE(HAVE_FRONT_END, 1, [Define to 1 if running slurmd on front-end only])
+  fi
+  AC_MSG_RESULT([${x_ac_front_end=no}])
+
   ]
 )
diff --git a/configure b/configure
index 869d92083c3..35f19c33476 100755
--- a/configure
+++ b/configure
@@ -1577,6 +1577,7 @@ Optional Features:
   --enable-debug          enable debugging code for development
   --enable-memory-leak-debug
                           enable memory leak debugging code for development
+  --enable-front-end      enable slurmd operation on a front-end
   --enable-load-env-no-login
                           enable --get-user-env option to load user
                           environment without login
@@ -7119,7 +7120,7 @@ ia64-*-hpux*)
   ;;
 *-*-irix6*)
   # Find out which ABI we are using.
-  echo '#line 7122 "configure"' > conftest.$ac_ext
+  echo '#line 7123 "configure"' > conftest.$ac_ext
   if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   (eval $ac_compile) 2>&5
   ac_status=$?
@@ -9225,11 +9226,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:9228: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:9229: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:9232: \$? = $ac_status" >&5
+   echo "$as_me:9233: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -9515,11 +9516,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:9518: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:9519: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:9522: \$? = $ac_status" >&5
+   echo "$as_me:9523: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -9619,11 +9620,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:9622: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:9623: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:9626: \$? = $ac_status" >&5
+   echo "$as_me:9627: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -11996,7 +11997,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<EOF
-#line 11999 "configure"
+#line 12000 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -12096,7 +12097,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<EOF
-#line 12099 "configure"
+#line 12100 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -14497,11 +14498,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:14500: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:14501: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:14504: \$? = $ac_status" >&5
+   echo "$as_me:14505: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -14601,11 +14602,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:14604: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:14605: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:14608: \$? = $ac_status" >&5
+   echo "$as_me:14609: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -16199,11 +16200,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:16202: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:16203: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:16206: \$? = $ac_status" >&5
+   echo "$as_me:16207: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -16303,11 +16304,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:16306: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:16307: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:16310: \$? = $ac_status" >&5
+   echo "$as_me:16311: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -18523,11 +18524,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:18526: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:18527: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:18530: \$? = $ac_status" >&5
+   echo "$as_me:18531: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -18813,11 +18814,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:18816: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:18817: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:18820: \$? = $ac_status" >&5
+   echo "$as_me:18821: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -18917,11 +18918,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:18920: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:18921: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:18924: \$? = $ac_status" >&5
+   echo "$as_me:18925: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -25989,6 +25990,33 @@ _ACEOF
   { echo "$as_me:$LINENO: result: ${x_ac_memory_debug=no}" >&5
 echo "${ECHO_T}${x_ac_memory_debug=no}" >&6; }
 
+  { echo "$as_me:$LINENO: checking whether to enable slurmd operation on a front-end" >&5
+echo $ECHO_N "checking whether to enable slurmd operation on a front-end... $ECHO_C" >&6; }
+  # Check whether --enable-front-end was given.
+if test "${enable_front_end+set}" = set; then
+  enableval=$enable_front_end;  case "$enableval" in
+        yes) x_ac_front_end=yes ;;
+         no) x_ac_front_end=no ;;
+          *) { echo "$as_me:$LINENO: result: doh!" >&5
+echo "${ECHO_T}doh!" >&6; }
+             { { echo "$as_me:$LINENO: error: bad value \"$enableval\" for --enable-front-end" >&5
+echo "$as_me: error: bad value \"$enableval\" for --enable-front-end" >&2;}
+   { (exit 1); exit 1; }; } ;;
+      esac
+
+
+fi
+
+  if test "$x_ac_front_end" = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_FRONT_END 1
+_ACEOF
+
+  fi
+  { echo "$as_me:$LINENO: result: ${x_ac_front_end=no}" >&5
+echo "${ECHO_T}${x_ac_front_end=no}" >&6; }
+
 
 
  if test "x$ac_debug" = "xtrue"; then
diff --git a/doc/html/accounting.shtml b/doc/html/accounting.shtml
index b1f2804f901..4f67cb5242b 100644
--- a/doc/html/accounting.shtml
+++ b/doc/html/accounting.shtml
@@ -222,7 +222,12 @@ is not in the database, then set this to "1".
 user names and optional partition name.)
 Without AccountingStorageEnforce being set (the default behavior) 
 jobs will be executed based upon policies configured in SLURM on each cluster. 
-This option will prevent users from accessing invalid accounts.</li>
+This option will prevent users from accessing invalid accounts.  
+Setting this to "2" will also cause association limits to be
+enforced.  When set to "1" association limits will not be
+enforced.  It is a good idea to run in this mode when running a
+scheduler on top of slurm, like Moab, that does not update in real
+time their limits per association.</li>
 
 <li><b>AccountingStorageHost</b>: The name or address of the host where 
 SlurmDBD executes</li>
diff --git a/doc/html/faq.shtml b/doc/html/faq.shtml
index 3842e1ed655..2063ed8f206 100644
--- a/doc/html/faq.shtml
+++ b/doc/html/faq.shtml
@@ -737,25 +737,7 @@ of the node that it is supposed to serve on the execute line.</li>
 for this due to it's improved support for multiple slurmd daemons.
 See the
 <a href="programmer_guide.shtml#multiple_slurmd_support">Programmers Guide</a>
-for more details about configuring multiple slurmd support.
-<p>In order to emulate a really large cluster, it can be more 
-convenient to use a single <i>slurmd</i> daemon. 
-That daemon will not be able to launch many tasks, but can 
-suffice for developing or testing scheduling software.
-<ol>
-<li>Execute the <i>configure</i> program with your normal options.</li>
-<li>Add the line "<i>#define HAVE_FRONT_END 1</i>" to the resulting
-<i>config.h</i> file.</li>
-<li>Build and install SLURM in the usual manner.</li>
-<li>In <i>slurm.conf</i> define the desired node names (arbitrary
-names used only by SLURM) as <i>NodeName</i> along with the actual
-address of the <b>one</b> physical node in <i>NodeHostname</i>.
-Up to 64k nodes can be configured in this virtual cluster.</li>
-<li>Start your <i>slurmctld</i> and one <i>slurmd</i> daemon.</li>
-<li>Create job allocations as desired, but <b>do not run job steps
-with more than a couple of tasks.</b> Doing so may result in the 
-<i>slurmd</i> daemon exhausting its memory and failing.</li>
-</ol>
+for more details about configuring multiple slurmd support.</p>
 
 <p>In order to emulate a really large cluster, it can be more 
 convenient to use a single <i>slurmd</i> daemon. 
@@ -767,9 +749,9 @@ Doing so may result in the <i>slurmd</i> daemon exhausting its
 memory and failing. 
 <b>Use this method with caution.</b>
 <ol>
-<li>Execute the <i>configure</i> program with your normal options.</li>
-<li>Append the line "<i>#define HAVE_FRONT_END 1</i>" to the resulting
-<i>config.h</i> file.</li>
+<li>Execute the <i>configure</i> program with your normal options
+plus <i>--enable-front-end</i> (this will define HAVE_FRONT_END in
+the resulting <i>config.h</i> file.</li>
 <li>Build and install SLURM in the usual manner.</li>
 <li>In <i>slurm.conf</i> define the desired node names (arbitrary
 names used only by SLURM) as <i>NodeName</i> along with the actual
@@ -783,9 +765,9 @@ Be sure to use the "-c" option when switch from this mode too.</li>
 <li>Create job allocations as desired, but do not run job steps
 with more than a couple of tasks.</li>
 </ol>
+
 <pre>
-$ ./configure --enable-debug --prefix=... --sysconfdir=...
-$ echo "#define HAVE_FRONT_END 1" >>config.h
+$ ./configure --enable-debug --enable-front-end --prefix=... --sysconfdir=...
 $ make install
 $ grep NodeHostName slurm.conf
 <i>NodeName=dummy[1-1200] NodeHostName=localhost NodeAddr=127.0.0.1</i>
@@ -1036,6 +1018,6 @@ Index: src/slurmctld/ping_nodes.c
 
 <p class="footer"><a href="#top">top</a></p>
 
-<p style="text-align:center;">Last modified 24 September 2008</p>
+<p style="text-align:center;">Last modified 7 October 2008</p>
 
 <!--#include virtual="footer.txt"-->
diff --git a/doc/html/programmer_guide.shtml b/doc/html/programmer_guide.shtml
index 2ee1d221f64..74d13cfd2af 100644
--- a/doc/html/programmer_guide.shtml
+++ b/doc/html/programmer_guide.shtml
@@ -170,8 +170,9 @@ Update <b>Makefile.am</b> files as needed then execute
 
 <h2>Tricks of the Trade</h2>
 <h3>HAVE_FRONT_END</h3>
-<p>You can make a single node appear to SLURM as a Linux cluster by manually 
-defining <b>HAVE_FRONT_END</b> to have a non-zero value in the file <b>config.h</b>.
+<p>You can make a single node appear to SLURM as a Linux cluster by running
+<i>configure</i> with the <i>--enable-front-end</i> option. This 
+defines b>HAVE_FRONT_END</b> with a non-zero value in the file <b>config.h</b>.
 All (fake) nodes should be defined in the <b>slurm.conf</b> file.
 These nodes should be configured with a single <b>NodeAddr</b> value
 indicating the node on which single <span class="commandline">slurmd</span> daemon 
@@ -229,6 +230,6 @@ host1> slurmd -N foo21
 
 <p class="footer"><a href="#top">top</a></p>
 
-<p style="text-align:center;">Last modified 20 May 2008</p>
+<p style="text-align:center;">Last modified 7 October 2008</p>
 
 <!--#include virtual="footer.txt"-->
diff --git a/doc/html/sched_policy.shtml b/doc/html/sched_policy.shtml
index b7a23b530b7..53aed3fd9dd 100644
--- a/doc/html/sched_policy.shtml
+++ b/doc/html/sched_policy.shtml
@@ -40,7 +40,14 @@ In order to enforce scheduling policy, set the value of
 <b>AccountingStorageEnforce</b> to "1" in <b>slurm.conf</b>.
 This prevents users from running any jobs without an valid
 <i>association</i> record in the database and enforces scheduling 
-policy limits that have been configured.</p>
+policy limits that have been configured.  
+In order to enforce association limits along with scheduling policy,
+set the value of <b>AccountingStorageEnforce</b> to "2"
+in <b>slurm.conf</b>.  When set to "1" association limits will not be
+enforced.  It is a good idea to run in this mode when running a
+scheduler on top of slurm, like Moab, that does not update in real
+time their limits per association.
+</p>
 
 <h2>Tools</h2>
 
diff --git a/src/common/assoc_mgr.c b/src/common/assoc_mgr.c
index 856a19bbd82..aafe757d127 100644
--- a/src/common/assoc_mgr.c
+++ b/src/common/assoc_mgr.c
@@ -385,6 +385,7 @@ static int _refresh_local_association_list(void *db_conn, int enforce)
 		if(!assoc) 
 			continue;
 		assoc->used_jobs = curr_assoc->used_jobs;
+		assoc->used_submit_jobs = curr_assoc->used_submit_jobs;
 		assoc->used_shares = curr_assoc->used_shares;
 		list_iterator_reset(local_itr);			
 	}
diff --git a/src/common/slurm_accounting_storage.c b/src/common/slurm_accounting_storage.c
index cdc69095981..2c4ee965935 100644
--- a/src/common/slurm_accounting_storage.c
+++ b/src/common/slurm_accounting_storage.c
@@ -4094,7 +4094,8 @@ extern uint32_t str_2_acct_qos(List qos_list, char *level)
 {
 	ListIterator itr = NULL;
 	acct_qos_rec_t *qos = NULL;
-	
+	char *working_level = NULL;
+
 	if(!qos_list) {
 		error("We need a qos list to translate");
 		return NO_VAL;
@@ -4102,11 +4103,15 @@ extern uint32_t str_2_acct_qos(List qos_list, char *level)
 		debug2("no level");
 		return 0;
 	}
-
+	if(level[0] == '+' || level[0] == '-')
+		working_level = level+1;
+	else
+		working_level = level;
 
 	itr = list_iterator_create(qos_list);
 	while((qos = list_next(itr))) {
-		if(!strncasecmp(level, qos->name, strlen(level)))
+		if(!strncasecmp(working_level, qos->name, 
+				strlen(working_level)))
 			break;
 	}
 	list_iterator_destroy(itr);
@@ -4214,18 +4219,29 @@ extern char *get_qos_complete_str(List qos_list, List num_qos_list)
 	char *temp_char = NULL;
 	char *print_this = NULL;
 	ListIterator itr = NULL;
+	int option = 0;
 
 	if(!qos_list || !list_count(qos_list)
 	   || !num_qos_list || !list_count(num_qos_list))
 		return xstrdup("");
 
-	temp_list = list_create(NULL);
+	temp_list = list_create(slurm_destroy_char);
 
 	itr = list_iterator_create(num_qos_list);
 	while((temp_char = list_next(itr))) {
+		option = 0;
+		if(temp_char[0] == '+' || temp_char[0] == '-') {
+			option = temp_char[0];
+			temp_char++;
+		}
 		temp_char = acct_qos_str(qos_list, atoi(temp_char));
-		if(temp_char)
-			list_append(temp_list, temp_char);
+		if(temp_char) {
+			if(option) 
+				list_append(temp_list, xstrdup_printf(
+						    "%c%s", option, temp_char));
+			else 
+				list_append(temp_list, xstrdup(temp_char));
+		}
 	}
 	list_iterator_destroy(itr);
 	list_sort(temp_list, (ListCmpF)slurm_sort_char_list_asc);
diff --git a/src/plugins/accounting_storage/mysql/accounting_storage_mysql.c b/src/plugins/accounting_storage/mysql/accounting_storage_mysql.c
index 125b7d6f25a..d1753a3912f 100644
--- a/src/plugins/accounting_storage/mysql/accounting_storage_mysql.c
+++ b/src/plugins/accounting_storage/mysql/accounting_storage_mysql.c
@@ -350,20 +350,29 @@ static int _setup_association_limits(acct_association_rec_t *assoc,
 
 	if((qos_level != QOS_LEVEL_MODIFY)
 	   && assoc->qos_list && list_count(assoc->qos_list)) {
+		char *qos_type = "qos";
 		char *qos_val = NULL;
 		char *tmp_char = NULL;
+		int set = 0;
 		ListIterator qos_itr = 
 			list_iterator_create(assoc->qos_list);
 		
-		xstrcat(*cols, ", qos");
-		
-		while((tmp_char = list_next(qos_itr))) 
+		while((tmp_char = list_next(qos_itr))) {
+			if(!set) {
+				if(tmp_char[0] == '+' || tmp_char[0] == '-')
+					qos_type = "delta_qos";
+				set = 1;
+			}
 			xstrfmtcat(qos_val, ",%s", tmp_char);
-		
+		}
+
 		list_iterator_destroy(qos_itr);
+
+		xstrfmtcat(*cols, ", %s", qos_type);
+		
 		
 		xstrfmtcat(*vals, ", '%s'", qos_val); 		
-		xstrfmtcat(*extra, ", qos='%s'", qos_val); 
+		xstrfmtcat(*extra, ", %s='%s'", qos_type, qos_val); 
 		xfree(qos_val);
 	} else if((qos_level == QOS_LEVEL_SET) && (normal_qos_id != NO_VAL)) { 
 		/* Add normal qos to the account */
diff --git a/src/sacctmgr/account_functions.c b/src/sacctmgr/account_functions.c
index 16e45fa7c73..c1c75fdef05 100644
--- a/src/sacctmgr/account_functions.c
+++ b/src/sacctmgr/account_functions.c
@@ -236,6 +236,11 @@ static int _set_cond(int *start, int argc, char *argv[],
 					db_conn, my_uid, NULL);
 			}
 			
+			if(end > 2 && argv[i][end-1] == '='
+			   && (argv[i][end-2] == '+' 
+			       || argv[i][end-2] == '-'))
+				option = (int)argv[i][end-2];
+
 			if(addto_qos_char_list(assoc_cond->qos_list, qos_list,
 					       argv[i]+end, option))
 				a_set = 1;
diff --git a/src/sacctmgr/cluster_functions.c b/src/sacctmgr/cluster_functions.c
index 6221dfd56fc..eeb9f074637 100644
--- a/src/sacctmgr/cluster_functions.c
+++ b/src/sacctmgr/cluster_functions.c
@@ -913,6 +913,7 @@ extern int sacctmgr_dump_cluster (int argc, char *argv[])
 
 	memset(&assoc_cond, 0, sizeof(acct_association_cond_t));
 	assoc_cond.without_parent_limits = 1;
+	assoc_cond.with_raw_qos = 1;
 	assoc_cond.cluster_list = list_create(NULL);
 	list_append(assoc_cond.cluster_list, cluster_name);
 
diff --git a/src/sacctmgr/common.c b/src/sacctmgr/common.c
index 9b3b83c3513..aea230c894c 100644
--- a/src/sacctmgr/common.c
+++ b/src/sacctmgr/common.c
@@ -482,13 +482,19 @@ extern acct_qos_rec_t *sacctmgr_find_qos_from_list(
 {
 	ListIterator itr = NULL;
 	acct_qos_rec_t *qos = NULL;
+	char *working_name = NULL;
 	
 	if(!name || !qos_list)
 		return NULL;
+
+	if(name[0] == '+' || name[0] == '-')
+		working_name = name+1;
+	else
+		working_name = name;
 	
 	itr = list_iterator_create(qos_list);
 	while((qos = list_next(itr))) {
-		if(!strcasecmp(name, qos->name))
+		if(!strcasecmp(working_name, qos->name))
 			break;
 	}
 	list_iterator_destroy(itr);
@@ -612,6 +618,8 @@ extern int addto_qos_char_list(List char_list, List qos_list, char *names,
 	int quote = 0;
 	uint32_t id=0;
 	int count = 0;
+	int equal_set = 0;
+	int add_set = 0;
 
 	if(!char_list) {
 		error("No list was given to fill in");
@@ -639,6 +647,12 @@ extern int addto_qos_char_list(List char_list, List qos_list, char *names,
 				names[i] = '`';
 			else if(names[i] == ',') {
 				if((i-start) > 0) {
+					int tmp_option = option;
+					if(names[start] == '+' 
+					   || names[start] == '-') {
+						tmp_option = names[start];
+						start++;
+					}
 					name = xmalloc((i-start+1));
 					memcpy(name, names+start, (i-start));
 					
@@ -657,11 +671,36 @@ extern int addto_qos_char_list(List char_list, List qos_list, char *names,
 					}
 					xfree(name);
 					
-					if(option) {
+					if(tmp_option) {
+						if(equal_set) {
+							error("You can't set "
+							      "qos equal to "
+							      "something and "
+							      "then add or "
+							      "subtract from "
+							      "it in the same "
+							      "line");
+							exit_code = 1;
+							break;
+						}
+						add_set = 1;
 						name = xstrdup_printf(
-							"%c%u", option, id);
-					} else
+							"%c%u", tmp_option, id);
+					} else {
+						if(add_set) {
+							error("You can't set "
+							      "qos equal to "
+							      "something and "
+							      "then add or "
+							      "subtract from "
+							      "it in the same "
+							      "line");
+							exit_code = 1;
+							break;
+						}
+						equal_set = 1;
 						name = xstrdup_printf("%u", id);
+					}
 					while((tmp_char = list_next(itr))) {
 						if(!strcasecmp(tmp_char, name))
 							break;
@@ -691,6 +730,11 @@ extern int addto_qos_char_list(List char_list, List qos_list, char *names,
 			i++;
 		}
 		if((i-start) > 0) {
+			int tmp_option = option;
+			if(names[start] == '+' || names[start] == '-') {
+				tmp_option = names[start];
+				start++;
+			}
 			name = xmalloc((i-start)+1);
 			memcpy(name, names+start, (i-start));
 			
@@ -706,12 +750,35 @@ extern int addto_qos_char_list(List char_list, List qos_list, char *names,
 				goto end_it;
 			}
 			xfree(name);
-			
-			if(option) {
+
+			if(tmp_option) {
+				if(equal_set) {
+					error("You can't set "
+					      "qos equal to "
+					      "something and "
+					      "then add or "
+					      "subtract from "
+					      "it in the same "
+					      "line");
+					exit_code = 1;
+					goto end_it;
+				}
 				name = xstrdup_printf(
-					"%c%u", option, id);
-			} else
+					"%c%u", tmp_option, id);
+			} else {
+				if(add_set) {
+					error("You can't set "
+					      "qos equal to "
+					      "something and "
+					      "then add or "
+					      "subtract from "
+					      "it in the same "
+					      "line");
+					exit_code = 1;
+					goto end_it;
+				}
 				name = xstrdup_printf("%u", id);
+			}
 			while((tmp_char = list_next(itr))) {
 				if(!strcasecmp(tmp_char, name))
 					break;
diff --git a/src/sacctmgr/file_functions.c b/src/sacctmgr/file_functions.c
index 1135a263ae8..974a6eb37fb 100644
--- a/src/sacctmgr/file_functions.c
+++ b/src/sacctmgr/file_functions.c
@@ -1958,6 +1958,7 @@ extern void load_sacctmgr_cfg_file (int argc, char *argv[])
 			
 			memset(&assoc_cond, 0, sizeof(acct_association_cond_t));
 			assoc_cond.cluster_list = list_create(NULL);
+			assoc_cond.with_raw_qos = 1;
 			assoc_cond.without_parent_limits = 1;
 			list_append(assoc_cond.cluster_list, cluster_name);
 			curr_assoc_list = acct_storage_g_get_associations(
diff --git a/src/sacctmgr/user_functions.c b/src/sacctmgr/user_functions.c
index 2e402d8fb46..4a5b9cd9bce 100644
--- a/src/sacctmgr/user_functions.c
+++ b/src/sacctmgr/user_functions.c
@@ -562,7 +562,6 @@ extern int sacctmgr_add_user(int argc, char *argv[])
 	char *default_acct = NULL;
 	acct_association_cond_t *assoc_cond = NULL;
 	acct_association_cond_t query_assoc_cond;
-	List add_qos_list = NULL;
 	List qos_list = NULL;
 	acct_admin_level_t admin_level = ACCT_ADMIN_NOTSET;
 	char *name = NULL, *account = NULL, *cluster = NULL, *partition = NULL;
@@ -686,13 +685,18 @@ extern int sacctmgr_add_user(int argc, char *argv[])
 		} else if (!strncasecmp (argv[i], "QosLevel", 1)) {
 			int option = 0;
 			if(!start_assoc.qos_list) 
-				add_qos_list = 
+				start_assoc.qos_list = 
 					list_create(slurm_destroy_char);
 			
 			if(!qos_list) 
 				qos_list = acct_storage_g_get_qos(
 					db_conn, my_uid, NULL);
 			
+			if(end > 2 && argv[i][end-1] == '='
+			   && (argv[i][end-2] == '+' 
+			       || argv[i][end-2] == '-'))
+				option = (int)argv[i][end-2];
+
 			if(addto_qos_char_list(start_assoc.qos_list, qos_list,
 					       argv[i]+end, option))
 				limit_set = 1;
@@ -847,7 +851,7 @@ extern int sacctmgr_add_user(int argc, char *argv[])
 					xfree(warning);
 					rc = SLURM_ERROR;
 					list_flush(user_list);
-					goto no_default;
+					goto end_it;
 				}
 				xfree(warning);
 			}
@@ -1083,8 +1087,6 @@ no_default:
 	}
 
 end_it:
-	if(add_qos_list)
-		list_destroy(add_qos_list);
 	list_destroy(user_list);
 	list_destroy(assoc_list);
 	xfree(default_acct);
diff --git a/src/slurmctld/job_mgr.c b/src/slurmctld/job_mgr.c
index 09026ca4758..ae59d9fc2f3 100644
--- a/src/slurmctld/job_mgr.c
+++ b/src/slurmctld/job_mgr.c
@@ -2082,19 +2082,9 @@ static int _job_create(job_desc_msg_t * job_desc, int allocate, int will_run,
 		return error_code;
 	}
 
-	debug3("before alteration asking for nodes %u-%u procs %u", 
-	       job_desc->min_nodes, job_desc->max_nodes,
-	       job_desc->num_procs);
-	select_g_alter_node_cnt(SELECT_SET_NODE_CNT, job_desc);
-	select_g_get_jobinfo(job_desc->select_jobinfo,
-			     SELECT_DATA_MAX_PROCS, &max_procs);
-	debug3("after alteration asking for nodes %u-%u procs %u-%u", 
-	       job_desc->min_nodes, job_desc->max_nodes,
-	       job_desc->num_procs, max_procs);
-	
 	if ((error_code = _validate_job_desc(job_desc, allocate, submit_uid)))
 		return error_code;
- 
+
 	if ((job_desc->user_id == 0) && part_ptr->disable_root_jobs) {
 		error("Security violation, SUBMIT_JOB for user root disabled");
 		return ESLURM_USER_ID_MISSING;
@@ -2154,6 +2144,19 @@ static int _job_create(job_desc_msg_t * job_desc, int allocate, int will_run,
 		return error_code;
 	}
 
+	/* This needs to be done after the association acct policy check since
+	 * it looks at unaltered nodes for bluegene systems
+	 */
+	debug3("before alteration asking for nodes %u-%u procs %u", 
+	       job_desc->min_nodes, job_desc->max_nodes,
+	       job_desc->num_procs);
+	select_g_alter_node_cnt(SELECT_SET_NODE_CNT, job_desc);
+	select_g_get_jobinfo(job_desc->select_jobinfo,
+			     SELECT_DATA_MAX_PROCS, &max_procs);
+	debug3("after alteration asking for nodes %u-%u procs %u-%u", 
+	       job_desc->min_nodes, job_desc->max_nodes,
+	       job_desc->num_procs, max_procs);
+	
 	/* check if select partition has sufficient resources to satisfy
 	 * the request */
 
diff --git a/src/slurmctld/proc_req.c b/src/slurmctld/proc_req.c
index 70b5826a919..e7089ec202e 100644
--- a/src/slurmctld/proc_req.c
+++ b/src/slurmctld/proc_req.c
@@ -2951,7 +2951,10 @@ inline static void  _slurm_rpc_accounting_update_msg(slurm_msg_t *msg)
 	START_TIMER;
 	debug2("Processing RPC: ACCOUNTING_UPDATE_MSG from uid=%u",
 		(unsigned int) uid);
-	if (!validate_super_user(uid)) {
+
+	if (!validate_super_user(uid) 
+	    && (assoc_mgr_get_admin_level(acct_db_conn, uid)
+		< ACCT_ADMIN_SUPER_USER)) {
 		error("Update Association request from non-super user uid=%d", 
 		      uid);
 		slurm_send_rc_msg(msg, EACCES);
-- 
GitLab