[tor-commits] [tor/master] Change the logic for the default for MaxMemInQueues

nickm at torproject.org nickm at torproject.org
Thu Apr 24 14:32:26 UTC 2014


commit 17ecd04fde2fd98b0cca3afb251b7173e22d3f42
Author: Nick Mathewson <nickm at torproject.org>
Date:   Thu Apr 3 12:06:44 2014 -0400

    Change the logic for the default for MaxMemInQueues
    
    If we can't detect the physical memory, the new default is 8 GB on
    64-bit architectures, and 1 GB on 32-bit architectures.
    
    If we *can* detect the physical memory, the new default is
      CLAMP(256 MB, phys_mem * 0.75, MAX_DFLT)
    where MAX_DFLT is 8 GB on 64-bit architectures and 2 GB on 32-bit
    architectures.
    
    You can still override the default by hand.  The logic here is simply
    trying to choose a lower default value on systems with less than 12 GB
    of physical RAM.
---
 changes/bug11396 |    7 ++++++
 doc/tor.1.txt    |    3 ++-
 src/or/config.c  |   74 +++++++++++++++++++++++++++++++++++++++++++++++++-----
 src/or/or.h      |    5 +++-
 4 files changed, 81 insertions(+), 8 deletions(-)

diff --git a/changes/bug11396 b/changes/bug11396
new file mode 100644
index 0000000..af94be0
--- /dev/null
+++ b/changes/bug11396
@@ -0,0 +1,7 @@
+  o Minor features (security):
+
+    - If you don't specify MaxMemInQueues yourself, Tor now tries to
+      pick a good value based on your total system memory. Previously,
+      the default was always 8 GB. You can still override the default by
+      setting MaxMemInQueues yourself. Resolves ticket 11396.
+
diff --git a/doc/tor.1.txt b/doc/tor.1.txt
index 1cc8f84..319921f 100644
--- a/doc/tor.1.txt
+++ b/doc/tor.1.txt
@@ -1752,7 +1752,8 @@ is non-zero):
     it has recovered at least 10% of this memory.  Do not set this option too
     low, or your relay may be unreliable under load.  This option only
     affects some queues, so the actual process size will be larger than
-    this. (Default: 8GB)
+    this.  If this option is set to 0, Tor will try to pick a reasonable
+    default based on your system's physical memory.  (Default: 0)
 
 DIRECTORY SERVER OPTIONS
 ------------------------
diff --git a/src/or/config.c b/src/or/config.c
index 4a6b301..78883cc 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -307,7 +307,7 @@ static config_var_t option_vars_[] = {
   V(MaxAdvertisedBandwidth,      MEMUNIT,  "1 GB"),
   V(MaxCircuitDirtiness,         INTERVAL, "10 minutes"),
   V(MaxClientCircuitsPending,    UINT,     "32"),
-  V(MaxMemInQueues,              MEMUNIT,  "8 GB"),
+  VAR("MaxMeminQueues",          MEMUNIT,   MaxMemInQueues_raw, "0"),
   OBSOLETE("MaxOnionsPending"),
   V(MaxOnionQueueDelay,          MSEC_INTERVAL, "1750 msec"),
   V(MinMeasuredBWsForAuthToIgnoreAdvertised, INT, "500"),
@@ -565,6 +565,8 @@ static void config_maybe_load_geoip_files_(const or_options_t *options,
 static int options_validate_cb(void *old_options, void *options,
                                void *default_options,
                                int from_setconf, char **msg);
+static uint64_t compute_real_max_mem_in_queues(const uint64_t val,
+                                               int log_guess);
 
 /** Magic value for or_options_t. */
 #define OR_OPTIONS_MAGIC 9090909
@@ -2793,11 +2795,9 @@ options_validate(or_options_t *old_options, or_options_t *options,
     REJECT("If EntryNodes is set, UseEntryGuards must be enabled.");
   }
 
-  if (options->MaxMemInQueues < (256 << 20)) {
-    log_warn(LD_CONFIG, "MaxMemInQueues must be at least 256 MB for now. "
-             "Ideally, have it as large as you can afford.");
-    options->MaxMemInQueues = (256 << 20);
-  }
+  options->MaxMemInQueues =
+    compute_real_max_mem_in_queues(options->MaxMemInQueues_raw,
+                                   server_mode(options));
 
   options->AllowInvalid_ = 0;
 
@@ -3547,6 +3547,68 @@ options_validate(or_options_t *old_options, or_options_t *options,
 #undef COMPLAIN
 }
 
+/* Given the value that the user has set for MaxMemInQueues, compute the
+ * actual maximum value.  We clip this value if it's too low, and autodetect
+ * it if it's set to 0. */
+static uint64_t
+compute_real_max_mem_in_queues(const uint64_t val, int log_guess)
+{
+  uint64_t result;
+
+  if (val == 0) {
+#define ONE_GIGABYTE (U64_LITERAL(1) << 30)
+#define ONE_MEGABYTE (U64_LITERAL(1) << 20)
+#if SIZEOF_VOID_P >= 8
+#define MAX_DEFAULT_MAXMEM (8*ONE_GIGABYTE)
+#else
+#define MAX_DEFAULT_MAXMEM (2*ONE_GIGABYTE)
+#endif
+    /* The user didn't pick a memory limit.  Choose a very large one
+     * that is still smaller than the system memory */
+    static int notice_sent = 0;
+    size_t ram = 0;
+    if (get_total_system_memory(&ram) < 0) {
+      /* We couldn't determine our total system memory!  */
+#if SIZEOF_VOID_P >= 8
+      /* 64-bit system.  Let's hope for 8 GB. */
+      result = 8 * ONE_GIGABYTE;
+#else
+      /* (presumably) 32-bit system. Let's hope for 1 GB. */
+      result = ONE_GIGABYTE;
+#endif
+    } else {
+      /* We detected it, so let's pick 3/4 of the total RAM as our limit. */
+      const uint64_t avail = (ram / 4) * 3;
+
+      /* Make sure it's in range from 0.25 GB to 8 GB. */
+      if (avail > MAX_DEFAULT_MAXMEM) {
+        /* If you want to use more than this much RAM, you need to configure
+           it yourself */
+        result = MAX_DEFAULT_MAXMEM;
+      } else if (avail < ONE_GIGABYTE / 4) {
+        result = ONE_GIGABYTE / 4;
+      } else {
+        result = avail;
+      }
+    }
+    if (log_guess && ! notice_sent) {
+      log_notice(LD_CONFIG, "%sMaxMemInQueues is set to "U64_FORMAT" MB. "
+                 "You can override this by setting MaxMemInQueues by hand.",
+                 ram ? "Based on detected system memory, " : "",
+                 U64_PRINTF_ARG(result / ONE_MEGABYTE));
+      notice_sent = 1;
+    }
+    return result;
+  } else if (val < ONE_GIGABYTE / 4) {
+    log_warn(LD_CONFIG, "MaxMemInQueues must be at least 256 MB for now. "
+             "Ideally, have it as large as you can afford.");
+    return ONE_GIGABYTE / 4;
+  } else {
+    /* The value was fine all along */
+    return val;
+  }
+}
+
 /** Helper: return true iff s1 and s2 are both NULL, or both non-NULL
  * equal strings. */
 static int
diff --git a/src/or/or.h b/src/or/or.h
index 38ab176..fa5a323 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -3474,7 +3474,10 @@ typedef struct {
   config_line_t *DirPort_lines;
   config_line_t *DNSPort_lines; /**< Ports to listen on for DNS requests. */
 
-  uint64_t MaxMemInQueues; /**< If we have more memory than this allocated
+  /* MaxMemInQueues value as input by the user. We clean this up to be
+   * MaxMemInQueues. */
+  uint64_t MaxMemInQueues_raw;
+  uint64_t MaxMemInQueues;/**< If we have more memory than this allocated
                             * for queues and buffers, run the OOM handler */
 
   /** @name port booleans





More information about the tor-commits mailing list