Tor  0.4.3.0-alpha-dev
conscache.c
Go to the documentation of this file.
1 /* Copyright (c) 2017-2020, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
3 
4 /**
5  * @file conscache.c
6  * @brief Consensus and diff on-disk cache.
7  **/
8 
9 #include "core/or/or.h"
10 
11 #include "app/config/config.h"
14 #include "lib/fs/storagedir.h"
15 #include "lib/encoding/confline.h"
16 
17 #define CCE_MAGIC 0x17162253
18 
19 #ifdef _WIN32
20 /* On Windows, unlink won't work on a file if the file is actively mmap()ed.
21  * That forces us to be less aggressive about unlinking files, and causes other
22  * changes throughout our logic.
23  */
24 #define MUST_UNMAP_TO_UNLINK
25 #endif /* defined(_WIN32) */
26 
27 /**
28  * A consensus_cache_entry_t is a reference-counted handle to an
29  * item in a consensus_cache_t. It can be mmapped into RAM, or not,
30  * depending whether it's currently in use.
31  */
33  uint32_t magic; /**< Must be set to CCE_MAGIC */
34  HANDLE_ENTRY(consensus_cache_entry, consensus_cache_entry_t);
35  int32_t refcnt; /**< Reference count. */
36  unsigned can_remove : 1; /**< If true, we want to delete this file. */
37  /** If true, we intend to unmap this file as soon as we're done with it. */
38  unsigned release_aggressively : 1;
39 
40  /** Filename for this object within the storage_dir_t */
41  char *fname;
42  /** Labels associated with this object. Immutable once the object
43  * is created. */
45  /** Pointer to the cache that includes this entry (if any). */
47 
48  /** Since what time has this object been mapped into RAM, but with the cache
49  * being the only having a reference to it? */
50  time_t unused_since;
51  /** mmaped contents of the underlying file. May be NULL */
53  /** Length of the body within <b>map</b>. */
54  size_t bodylen;
55  /** Pointer to the body within <b>map</b>. */
56  const uint8_t *body;
57 };
58 
59 /**
60  * A consensus_cache_t holds a directory full of labeled items.
61  */
63  /** Underling storage_dir_t to handle persistence */
65  /** List of all the entries in the directory. */
67 
68  /** The maximum number of entries that we'd like to allow in this cache.
69  * This is the same as the storagedir limit when MUST_UNMAP_TO_UNLINK is
70  * not defined. */
71  unsigned max_entries;
72 };
73 
74 static void consensus_cache_clear(consensus_cache_t *cache);
79 
80 /**
81  * Helper: Open a consensus cache in subdirectory <b>subdir</b> of the
82  * data directory, to hold up to <b>max_entries</b> of data.
83  */
85 consensus_cache_open(const char *subdir, int max_entries)
86 {
87  int storagedir_max_entries;
88  consensus_cache_t *cache = tor_malloc_zero(sizeof(consensus_cache_t));
89  char *directory = get_cachedir_fname(subdir);
90  cache->max_entries = max_entries;
91 
92 #ifdef MUST_UNMAP_TO_UNLINK
93  /* If we can't unlink the files that we're still using, then we need to
94  * tell the storagedir backend to allow far more files than this consensus
95  * cache actually wants, so that it can hold files which, from this cache's
96  * perspective, have become useless.
97  */
98 #define VERY_LARGE_STORAGEDIR_LIMIT (1000*1000)
99  storagedir_max_entries = VERY_LARGE_STORAGEDIR_LIMIT;
100 #else /* !defined(MUST_UNMAP_TO_UNLINK) */
101  /* Otherwise, we can just tell the storagedir to use the same limits
102  * as this cache. */
103  storagedir_max_entries = max_entries;
104 #endif /* defined(MUST_UNMAP_TO_UNLINK) */
105 
106  cache->dir = storage_dir_new(directory, storagedir_max_entries);
107  tor_free(directory);
108  if (!cache->dir) {
109  tor_free(cache);
110  return NULL;
111  }
112 
113  consensus_cache_rescan(cache);
114  return cache;
115 }
116 
117 /** Return true if it's okay to put more entries in this cache than
118  * its official file limit.
119  *
120  * (We need this method on Windows, where we can't unlink files that are still
121  * in use, and therefore might need to temporarily exceed the file limit until
122  * the no-longer-wanted files are deletable.)
123  */
124 int
126 {
127  (void) cache;
128 #ifdef MUST_UNMAP_TO_UNLINK
129  return 1;
130 #else
131  return 0;
132 #endif
133 }
134 
135 /**
136  * Tell the sandbox (if any) configured by <b>cfg</b> to allow the
137  * operations that <b>cache</b> will need.
138  */
139 int
141  struct sandbox_cfg_elem_t **cfg)
142 {
143 #ifdef MUST_UNMAP_TO_UNLINK
144  /* Our Linux sandbox doesn't support huge file lists like the one that would
145  * be generated by using VERY_LARGE_STORAGEDIR_LIMIT above in
146  * consensus_cache_open(). Since the Linux sandbox is the only one we have
147  * right now, we just assert that we never reach this point when we've had
148  * to use VERY_LARGE_STORAGEDIR_LIMIT.
149  *
150  * If at some point in the future we have a different sandbox mechanism that
151  * can handle huge file lists, we can remove this assertion or make it
152  * conditional.
153  */
154  tor_assert_nonfatal_unreached();
155 #endif /* defined(MUST_UNMAP_TO_UNLINK) */
156  return storage_dir_register_with_sandbox(cache->dir, cfg);
157 }
158 
159 /**
160  * Helper: clear all entries from <b>cache</b> (but do not delete
161  * any that aren't marked for removal
162  */
163 static void
165 {
167 
169  ent->in_cache = NULL;
171  } SMARTLIST_FOREACH_END(ent);
172  smartlist_free(cache->entries);
173  cache->entries = NULL;
174 }
175 
176 /**
177  * Drop all storage held by <b>cache</b>.
178  */
179 void
181 {
182  if (! cache)
183  return;
184 
185  if (cache->entries) {
186  consensus_cache_clear(cache);
187  }
188  storage_dir_free(cache->dir);
189  tor_free(cache);
190 }
191 
192 /**
193  * Write <b>datalen</b> bytes of data at <b>data</b> into the <b>cache</b>,
194  * labeling that data with <b>labels</b>. On failure, return NULL. On
195  * success, return a newly created consensus_cache_entry_t.
196  *
197  * The returned value will be owned by the cache, and you will have a
198  * reference to it. Call consensus_cache_entry_decref() when you are
199  * done with it.
200  *
201  * The provided <b>labels</b> MUST have distinct keys: if they don't,
202  * this API does not specify which values (if any) for the duplicate keys
203  * will be considered.
204  */
207  const config_line_t *labels,
208  const uint8_t *data,
209  size_t datalen)
210 {
211  char *fname = NULL;
212  int r = storage_dir_save_labeled_to_file(cache->dir,
213  labels, data, datalen, &fname);
214  if (r < 0 || fname == NULL) {
215  return NULL;
216  }
218  tor_malloc_zero(sizeof(consensus_cache_entry_t));
219  ent->magic = CCE_MAGIC;
220  ent->fname = fname;
221  ent->labels = config_lines_dup(labels);
222  ent->in_cache = cache;
223  ent->unused_since = TIME_MAX;
224  smartlist_add(cache->entries, ent);
225  /* Start the reference count at 2: the caller owns one copy, and the
226  * cache owns another.
227  */
228  ent->refcnt = 2;
229 
230  return ent;
231 }
232 
233 /**
234  * Given a <b>cache</b>, return some entry for which <b>key</b>=<b>value</b>.
235  * Return NULL if no such entry exists.
236  *
237  * Does not adjust reference counts.
238  */
241  const char *key,
242  const char *value)
243 {
244  smartlist_t *tmp = smartlist_new();
245  consensus_cache_find_all(tmp, cache, key, value);
246  consensus_cache_entry_t *ent = NULL;
247  if (smartlist_len(tmp))
248  ent = smartlist_get(tmp, 0);
249  smartlist_free(tmp);
250  return ent;
251 }
252 
253 /**
254  * Given a <b>cache</b>, add every entry to <b>out</b> for which
255  * <b>key</b>=<b>value</b>. If <b>key</b> is NULL, add every entry.
256  *
257  * Do not add any entry that has been marked for removal.
258  *
259  * Does not adjust reference counts.
260  */
261 void
263  consensus_cache_t *cache,
264  const char *key,
265  const char *value)
266 {
268  if (ent->can_remove == 1) {
269  /* We want to delete this; pretend it isn't there. */
270  continue;
271  }
272  if (! key) {
273  smartlist_add(out, ent);
274  continue;
275  }
276  const char *found_val = consensus_cache_entry_get_value(ent, key);
277  if (found_val && !strcmp(value, found_val)) {
278  smartlist_add(out, ent);
279  }
280  } SMARTLIST_FOREACH_END(ent);
281 }
282 
283 /**
284  * Given a list of consensus_cache_entry_t, remove all those entries
285  * that do not have <b>key</b>=<b>value</b> in their labels.
286  *
287  * Does not adjust reference counts.
288  */
289 void
291  const char *key,
292  const char *value)
293 {
294  if (BUG(lst == NULL))
295  return; // LCOV_EXCL_LINE
296  if (key == NULL)
297  return;
299  const char *found_val = consensus_cache_entry_get_value(ent, key);
300  if (! found_val || strcmp(value, found_val)) {
301  SMARTLIST_DEL_CURRENT(lst, ent);
302  }
303  } SMARTLIST_FOREACH_END(ent);
304 }
305 
306 /**
307  * If <b>ent</b> has a label with the given <b>key</b>, return its
308  * value. Otherwise return NULL.
309  *
310  * The return value is only guaranteed to be valid for as long as you
311  * hold a reference to <b>ent</b>.
312  */
313 const char *
315  const char *key)
316 {
317  const config_line_t *match = config_line_find(ent->labels, key);
318  if (match)
319  return match->value;
320  else
321  return NULL;
322 }
323 
324 /**
325  * Return a pointer to the labels in <b>ent</b>.
326  *
327  * This pointer is only guaranteed to be valid for as long as you
328  * hold a reference to <b>ent</b>.
329  */
330 const config_line_t *
332 {
333  return ent->labels;
334 }
335 
336 /**
337  * Increase the reference count of <b>ent</b>.
338  */
339 void
341 {
342  if (BUG(ent->magic != CCE_MAGIC))
343  return; // LCOV_EXCL_LINE
344  ++ent->refcnt;
345  ent->unused_since = TIME_MAX;
346 }
347 
348 /**
349  * Release a reference held to <b>ent</b>.
350  *
351  * If it was the last reference, ent will be freed. Therefore, you must not
352  * use <b>ent</b> after calling this function.
353  */
354 void
356 {
357  if (! ent)
358  return;
359  if (BUG(ent->refcnt <= 0))
360  return; // LCOV_EXCL_LINE
361  if (BUG(ent->magic != CCE_MAGIC))
362  return; // LCOV_EXCL_LINE
363 
364  --ent->refcnt;
365 
366  if (ent->refcnt == 1 && ent->in_cache) {
367  /* Only the cache has a reference: we don't need to keep the file
368  * mapped */
369  if (ent->map) {
370  if (ent->release_aggressively) {
372  } else {
373  ent->unused_since = approx_time();
374  }
375  }
376  return;
377  }
378 
379  if (ent->refcnt > 0)
380  return;
381 
382  /* Refcount is zero; we can free it. */
383  if (ent->map) {
385  }
386  tor_free(ent->fname);
387  config_free_lines(ent->labels);
388  consensus_cache_entry_handles_clear(ent);
389  memwipe(ent, 0, sizeof(consensus_cache_entry_t));
390  tor_free(ent);
391 }
392 
393 /**
394  * Mark <b>ent</b> for deletion from the cache. Deletion will not occur
395  * until the cache is the only place that holds a reference to <b>ent</b>.
396  */
397 void
399 {
400  ent->can_remove = 1;
401 }
402 
403 /**
404  * Mark <b>ent</b> as the kind of entry that we don't need to keep mmap'd for
405  * any longer than we're actually using it.
406  */
407 void
409 {
410  ent->release_aggressively = 1;
411 }
412 
413 /**
414  * Try to read the body of <b>ent</b> into memory if it isn't already
415  * loaded. On success, set *<b>body_out</b> to the body, *<b>sz_out</b>
416  * to its size, and return 0. On failure return -1.
417  *
418  * The resulting body pointer will only be valid for as long as you
419  * hold a reference to <b>ent</b>.
420  */
421 int
423  const uint8_t **body_out,
424  size_t *sz_out)
425 {
426  if (BUG(ent->magic != CCE_MAGIC))
427  return -1; // LCOV_EXCL_LINE
428 
429  if (! ent->map) {
430  if (! ent->in_cache)
431  return -1;
432 
434  (consensus_cache_entry_t *)ent);
435  if (! ent->map) {
436  return -1;
437  }
438  }
439 
440  *body_out = ent->body;
441  *sz_out = ent->bodylen;
442  return 0;
443 }
444 
445 /**
446  * Unmap every mmap'd element of <b>cache</b> that has been unused
447  * since <b>cutoff</b>.
448  */
449 void
451 {
453  tor_assert_nonfatal(ent->in_cache == cache);
454  if (ent->refcnt > 1 || BUG(ent->in_cache == NULL)) {
455  /* Somebody is using this entry right now */
456  continue;
457  }
458  if (ent->unused_since > cutoff) {
459  /* Has been unused only for a little while */
460  continue;
461  }
462  if (ent->map == NULL) {
463  /* Not actually mapped. */
464  continue;
465  }
467  } SMARTLIST_FOREACH_END(ent);
468 }
469 
470 /**
471  * Return the number of currently unused filenames available in this cache.
472  */
473 int
475 {
476  tor_assert(cache);
477  int max = cache->max_entries;
478  int used = smartlist_len(storage_dir_list(cache->dir));
479 #ifdef MUST_UNMAP_TO_UNLINK
480  if (used > max)
481  return 0;
482 #else
483  tor_assert_nonfatal(max >= used);
484 #endif /* defined(MUST_UNMAP_TO_UNLINK) */
485  return max - used;
486 }
487 
488 /**
489  * Delete every element of <b>cache</b> has been marked with
490  * consensus_cache_entry_mark_for_removal. If <b>force</b> is false,
491  * retain those entries which are in use by something other than the cache.
492  */
493 void
495 {
497  tor_assert_nonfatal(ent->in_cache == cache);
498  int force_ent = force;
499 #ifdef MUST_UNMAP_TO_UNLINK
500  /* We cannot delete anything with an active mmap on win32, so no
501  * force-deletion. */
502  if (ent->map) {
503  force_ent = 0;
504  }
505 #endif /* defined(MUST_UNMAP_TO_UNLINK) */
506  if (! force_ent) {
507  if (ent->refcnt > 1 || BUG(ent->in_cache == NULL)) {
508  /* Somebody is using this entry right now */
509  continue;
510  }
511  }
512  if (ent->can_remove == 0) {
513  /* Don't want to delete this. */
514  continue;
515  }
516  if (BUG(ent->refcnt <= 0)) {
517  continue; // LCOV_EXCL_LINE
518  }
519 
520  SMARTLIST_DEL_CURRENT(cache->entries, ent);
521  ent->in_cache = NULL;
522  char *fname = tor_strdup(ent->fname); /* save a copy */
524  storage_dir_remove_file(cache->dir, fname);
525  tor_free(fname);
526  } SMARTLIST_FOREACH_END(ent);
527 }
528 
529 /**
530  * Internal helper: rescan <b>cache</b> and rebuild its list of entries.
531  */
532 static void
534 {
535  if (cache->entries) {
536  consensus_cache_clear(cache);
537  }
538 
539  cache->entries = smartlist_new();
540  const smartlist_t *fnames = storage_dir_list(cache->dir);
541  SMARTLIST_FOREACH_BEGIN(fnames, const char *, fname) {
542  tor_mmap_t *map = NULL;
543  config_line_t *labels = NULL;
544  const uint8_t *body;
545  size_t bodylen;
546  map = storage_dir_map_labeled(cache->dir, fname,
547  &labels, &body, &bodylen);
548  if (! map) {
549  /* The ERANGE error might come from tor_mmap_file() -- it means the file
550  * was empty. EINVAL might come from ..map_labeled() -- it means the
551  * file was misformatted. In both cases, we should just delete it.
552  */
553  if (errno == ERANGE || errno == EINVAL) {
554  log_warn(LD_FS, "Found %s file %s in consensus cache; removing it.",
555  errno == ERANGE ? "empty" : "misformatted",
556  escaped(fname));
557  storage_dir_remove_file(cache->dir, fname);
558  } else {
559  /* Can't load this; continue */
560  log_warn(LD_FS, "Unable to map file %s from consensus cache: %s",
561  escaped(fname), strerror(errno));
562  }
563  continue;
564  }
566  tor_malloc_zero(sizeof(consensus_cache_entry_t));
567  ent->magic = CCE_MAGIC;
568  ent->fname = tor_strdup(fname);
569  ent->labels = labels;
570  ent->refcnt = 1;
571  ent->in_cache = cache;
572  ent->unused_since = TIME_MAX;
573  smartlist_add(cache->entries, ent);
574  tor_munmap_file(map); /* don't actually need to keep this around */
575  } SMARTLIST_FOREACH_END(fname);
576 }
577 
578 /**
579  * Make sure that <b>ent</b> is mapped into RAM.
580  */
581 static void
584 {
585  if (ent->map)
586  return;
587 
588  ent->map = storage_dir_map_labeled(cache->dir, ent->fname,
589  NULL, &ent->body, &ent->bodylen);
590  ent->unused_since = TIME_MAX;
591 }
592 
593 /**
594  * Unmap <b>ent</b> from RAM.
595  *
596  * Do not call this if something other than the cache is holding a reference
597  * to <b>ent</b>
598  */
599 static void
601 {
602  ent->unused_since = TIME_MAX;
603  if (!ent->map)
604  return;
605 
606  tor_munmap_file(ent->map);
607  ent->map = NULL;
608  ent->body = NULL;
609  ent->bodylen = 0;
610  ent->unused_since = TIME_MAX;
611 }
612 
613 HANDLE_IMPL(consensus_cache_entry, consensus_cache_entry_t, )
614 
615 #ifdef TOR_UNIT_TESTS
616 /**
617  * Testing only: Return true iff <b>ent</b> is mapped into memory.
618  *
619  * (In normal operation, this information is not exposed.)
620  */
621 int
622 consensus_cache_entry_is_mapped(consensus_cache_entry_t *ent)
623 {
624  if (ent->map) {
625  tor_assert(ent->body);
626  return 1;
627  } else {
628  tor_assert(!ent->body);
629  return 0;
630  }
631 }
632 #endif /* defined(TOR_UNIT_TESTS) */
size_t bodylen
Definition: conscache.c:54
void consensus_cache_delete_pending(consensus_cache_t *cache, int force)
Definition: conscache.c:494
uint32_t magic
Definition: conscache.c:33
consensus_cache_entry_t * consensus_cache_add(consensus_cache_t *cache, const config_line_t *labels, const uint8_t *data, size_t datalen)
Definition: conscache.c:206
const smartlist_t * storage_dir_list(storage_dir_t *d)
Definition: storagedir.c:179
const config_line_t * consensus_cache_entry_get_labels(const consensus_cache_entry_t *ent)
Definition: conscache.c:331
Header for confline.c.
char * fname
Definition: conscache.c:41
static void consensus_cache_entry_unmap(consensus_cache_entry_t *ent)
Definition: conscache.c:600
Header for conscache.c.
#define SMARTLIST_FOREACH_BEGIN(sl, type, var)
int32_t refcnt
Definition: conscache.c:35
int consensus_cache_entry_get_body(const consensus_cache_entry_t *ent, const uint8_t **body_out, size_t *sz_out)
Definition: conscache.c:422
unsigned can_remove
Definition: conscache.c:36
void smartlist_add(smartlist_t *sl, void *element)
const uint8_t * body
Definition: conscache.c:56
Header file for config.c.
#define tor_assert(expr)
Definition: util_bug.h:102
#define tor_free(p)
Definition: malloc.h:52
static void consensus_cache_entry_map(consensus_cache_t *, consensus_cache_entry_t *)
Definition: conscache.c:582
tor_mmap_t * storage_dir_map_labeled(storage_dir_t *dir, const char *fname, config_line_t **labels_out, const uint8_t **data_out, size_t *sz_out)
Definition: storagedir.c:399
Definition: conscache.c:32
#define SMARTLIST_DEL_CURRENT(sl, var)
static void consensus_cache_rescan(consensus_cache_t *)
Definition: conscache.c:533
void memwipe(void *mem, uint8_t byte, size_t sz)
Definition: crypto_util.c:55
smartlist_t * smartlist_new(void)
unsigned release_aggressively
Definition: conscache.c:38
const char * consensus_cache_entry_get_value(const consensus_cache_entry_t *ent, const char *key)
Definition: conscache.c:314
void consensus_cache_free_(consensus_cache_t *cache)
Definition: conscache.c:180
config_line_t * labels
Definition: conscache.c:44
void consensus_cache_entry_mark_for_removal(consensus_cache_entry_t *ent)
Definition: conscache.c:398
Common functions for cryptographic routines.
consensus_cache_t * in_cache
Definition: conscache.c:46
int consensus_cache_may_overallocate(consensus_cache_t *cache)
Definition: conscache.c:125
storage_dir_t * dir
Definition: conscache.c:64
Master header file for Tor-specific functionality.
consensus_cache_t * consensus_cache_open(const char *subdir, int max_entries)
Definition: conscache.c:85
void consensus_cache_entry_incref(consensus_cache_entry_t *ent)
Definition: conscache.c:340
consensus_cache_entry_t * consensus_cache_find_first(consensus_cache_t *cache, const char *key, const char *value)
Definition: conscache.c:240
int consensus_cache_register_with_sandbox(consensus_cache_t *cache, struct sandbox_cfg_elem_t **cfg)
Definition: conscache.c:140
int storage_dir_register_with_sandbox(storage_dir_t *d, sandbox_cfg_t **cfg)
Definition: storagedir.c:104
#define LD_FS
Definition: log.h:70
int storage_dir_save_labeled_to_file(storage_dir_t *d, const config_line_t *labels, const uint8_t *data, size_t length, char **fname_out)
Definition: storagedir.c:345
config_line_t * config_lines_dup(const config_line_t *inp)
Definition: confline.c:227
time_t unused_since
Definition: conscache.c:50
void consensus_cache_entry_mark_for_aggressive_release(consensus_cache_entry_t *ent)
Definition: conscache.c:408
const char * escaped(const char *s)
Definition: escape.c:126
const config_line_t * config_line_find(const config_line_t *lines, const char *key)
Definition: confline.c:74
void consensus_cache_unmap_lazy(consensus_cache_t *cache, time_t cutoff)
Definition: conscache.c:450
tor_mmap_t * map
Definition: conscache.c:52
Header for storagedir.c.
time_t approx_time(void)
Definition: approx_time.c:32
unsigned max_entries
Definition: conscache.c:71
void consensus_cache_filter_list(smartlist_t *lst, const char *key, const char *value)
Definition: conscache.c:290
void consensus_cache_find_all(smartlist_t *out, consensus_cache_t *cache, const char *key, const char *value)
Definition: conscache.c:262
void storage_dir_remove_file(storage_dir_t *d, const char *fname)
Definition: storagedir.c:480
int consensus_cache_get_n_filenames_available(consensus_cache_t *cache)
Definition: conscache.c:474
static void consensus_cache_clear(consensus_cache_t *cache)
Definition: conscache.c:164
void consensus_cache_entry_decref(consensus_cache_entry_t *ent)
Definition: conscache.c:355
smartlist_t * entries
Definition: conscache.c:66
storage_dir_t * storage_dir_new(const char *dirname, int max_files)
Definition: storagedir.c:68