Coverage Report

Created: 2026-10-16 06:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/haproxy/src/pool.c
Line
Count
Source
1
/*
2
 * Memory management functions.
3
 *
4
 * Copyright 2000-2007 Willy Tarreau <w@1wt.eu>
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version
9
 * 2 of the License, or (at your option) any later version.
10
 *
11
 */
12
13
#include <errno.h>
14
15
#include <import/plock.h>
16
17
#include <haproxy/activity.h>
18
#include <haproxy/api.h>
19
#include <haproxy/applet-t.h>
20
#include <haproxy/cfgparse.h>
21
#include <haproxy/channel.h>
22
#include <haproxy/cli.h>
23
#include <haproxy/clock.h>
24
#include <haproxy/errors.h>
25
#include <haproxy/global.h>
26
#include <haproxy/list.h>
27
#include <haproxy/pool.h>
28
#include <haproxy/pool-os.h>
29
#include <haproxy/sc_strm.h>
30
#include <haproxy/stconn.h>
31
#include <haproxy/sym.h>
32
#include <haproxy/thread.h>
33
#include <haproxy/tools.h>
34
35
36
/* These ones are initialized per-thread on startup by init_pools() */
37
THREAD_LOCAL size_t pool_cache_bytes = 0;                /* total cache size */
38
THREAD_LOCAL size_t pool_cache_count = 0;                /* #cache objects   */
39
40
struct list pools __read_mostly = LIST_HEAD_INIT(pools);
41
int mem_poison_byte __read_mostly = 'P';
42
int pool_trim_in_progress = 0;
43
uint pool_debugging __read_mostly =               /* set of POOL_DBG_* flags */
44
#if defined(DEBUG_FAIL_ALLOC) && (DEBUG_FAIL_ALLOC > 0)
45
  POOL_DBG_FAIL_ALLOC |
46
#endif
47
#if defined(DEBUG_DONT_SHARE_POOLS) && (DEBUG_DONT_SHARE_POOLS > 0)
48
  POOL_DBG_DONT_MERGE |
49
#endif
50
#if defined(DEBUG_POOL_INTEGRITY) && (DEBUG_POOL_INTEGRITY > 0)
51
  POOL_DBG_COLD_FIRST |
52
  POOL_DBG_INTEGRITY  |
53
#endif
54
#if defined(CONFIG_HAP_NO_GLOBAL_POOLS)
55
  POOL_DBG_NO_GLOBAL  |
56
#endif
57
#if defined(DEBUG_NO_POOLS) && (DEBUG_NO_POOLS > 0)
58
  POOL_DBG_NO_CACHE   |
59
#endif
60
#if defined(DEBUG_POOL_TRACING) && (DEBUG_POOL_TRACING > 0)
61
  POOL_DBG_CALLER     |
62
#endif
63
#if defined(DEBUG_MEMORY_POOLS) && (DEBUG_MEMORY_POOLS > 0)
64
  POOL_DBG_TAG        |
65
#endif
66
#if defined(DEBUG_UAF) && (DEBUG_UAF > 0)
67
  POOL_DBG_NO_CACHE   |
68
  POOL_DBG_UAF        |
69
#endif
70
  0;
71
72
static const struct {
73
  uint flg;
74
  const char *set;
75
  const char *clr;
76
  const char *hlp;
77
} dbg_options[] = {
78
  /* flg,                 set,          clr,            hlp */
79
  { POOL_DBG_FAIL_ALLOC, "fail",       "no-fail",      "randomly fail allocations" },
80
  { POOL_DBG_DONT_MERGE, "no-merge",   "merge",        "disable merging of similar pools" },
81
  { POOL_DBG_COLD_FIRST, "cold-first", "hot-first",    "pick cold objects first" },
82
  { POOL_DBG_INTEGRITY,  "integrity",  "no-integrity", "enable cache integrity checks" },
83
  { POOL_DBG_NO_GLOBAL,  "no-global",  "global",       "disable global shared cache" },
84
  { POOL_DBG_NO_CACHE,   "no-cache",   "cache",        "disable thread-local cache" },
85
  { POOL_DBG_CALLER,     "caller",     "no-caller",    "save caller information in cache" },
86
  { POOL_DBG_TAG,        "tag",        "no-tag",       "add tag at end of allocated objects" },
87
  { POOL_DBG_POISON,     "poison",     "no-poison",    "poison newly allocated objects" },
88
  { POOL_DBG_UAF,        "uaf",        "no-uaf",       "enable use-after-free checks (slow)" },
89
  { POOL_DBG_BACKUP,     "backup",     "no-backup",    "compare object contents on re-alloc" },
90
  { 0 /* end */ }
91
};
92
93
/* describes a snapshot of a pool line about to be dumped by "show pools" */
94
struct pool_dump_info {
95
  const struct pool_head *entry;
96
  ulong alloc_items;
97
  ulong alloc_bytes;
98
  ulong used_items;
99
  ulong cached_items;
100
  ulong need_avg;
101
  ulong failed_items;
102
};
103
104
/* context used by "show pools" */
105
struct show_pools_ctx {
106
  char *prefix;  /* if non-null, match this prefix name for the pool */
107
  int how;     /* bits 0..3: 0=no sort, 1=by name, 2=by item size, 3=by total alloc */
108
  int maxcnt;  /* 0=no limit, other=max number of output entries */
109
  int pool_idx; /* Index of the pool to restart the dump  (-1 means the header must be dumped) */
110
  unsigned int nbpools; /* total number of pools */
111
  unsigned long long allocated; /* total number of bytes allocated*/
112
  unsigned long long used; /* total number of bytes used */
113
  unsigned long long cached_bytes; /* total number of bytes cached */
114
  struct pool_dump_info *pool_info; /* array containing info about all pools (contains nbpools entries) */
115
};
116
117
static int mem_fail_rate __read_mostly = 0;
118
static int using_default_allocator __read_mostly = 1; // linked-in allocator or LD_PRELOADed one ?
119
static int disable_trim __read_mostly = 0;
120
static int(*my_mallctl)(const char *, void *, size_t *, void *, size_t) = NULL;
121
static int(*_malloc_trim)(size_t) = NULL;
122
123
/* returns the pool hash bucket an object should use based on its pointer.
124
 * Objects will needed consistent bucket assignment so that they may be
125
 * allocated on one thread and released on another one. Thus only the
126
 * pointer is usable.
127
 */
128
static forceinline unsigned int pool_pbucket(const void *ptr)
129
0
{
130
0
  return ptr_hash(ptr, CONFIG_HAP_POOL_BUCKETS_BITS);
131
0
}
132
133
/* returns the pool hash bucket to use for the current thread. This should only
134
 * be used when no pointer is available (e.g. count alloc failures).
135
 */
136
static forceinline unsigned int pool_tbucket(void)
137
0
{
138
0
  return tid % CONFIG_HAP_POOL_BUCKETS;
139
0
}
140
141
/* ask the allocator to trim memory pools.
142
 * This must run under thread isolation so that competing threads trying to
143
 * allocate or release memory do not prevent the allocator from completing
144
 * its job. We just have to be careful as callers might already be isolated
145
 * themselves.
146
 */
147
void trim_all_pools(void)
148
0
{
149
0
  int isolated = thread_isolated();
150
151
0
  if (!isolated)
152
0
    thread_isolate();
153
154
0
  malloc_trim(0);
155
156
0
  if (!isolated)
157
0
    thread_release();
158
0
}
159
160
/* check if we're using the same allocator as the one that provides
161
 * malloc_trim() and mallinfo(). The principle is that on glibc, both
162
 * malloc_trim() and mallinfo() are provided, and using mallinfo() we
163
 * can check if malloc() is performed through glibc or any other one
164
 * the executable was linked against (e.g. jemalloc). Prior to this we
165
 * have to check whether we're running on jemalloc by verifying if the
166
 * mallctl() function is provided. Its pointer will be used later.
167
 */
168
static void detect_allocator(void)
169
0
{
170
0
#if defined(__ELF__)
171
0
  extern int mallctl(const char *, void *, size_t *, void *, size_t) __attribute__((weak));
172
173
0
  my_mallctl = mallctl;
174
0
#endif
175
0
  if (!my_mallctl) {
176
    /* trick: we won't enter here if mallctl() is known at link
177
     * time. This allows to detect if the symbol was changed since
178
     * the program was linked, indicating it's not running on the
179
     * expected allocator (due to an LD_PRELOAD) and that we must
180
     * be extra cautious and avoid some optimizations that are
181
     * known to break such as malloc_trim().
182
     */
183
0
    my_mallctl = get_sym_curr_addr("mallctl");
184
0
    using_default_allocator = (my_mallctl == NULL);
185
0
  }
186
187
0
  if (!my_mallctl) {
188
0
#if defined(HA_HAVE_MALLOC_TRIM)
189
#ifdef HA_HAVE_MALLINFO2
190
    struct mallinfo2 mi1, mi2;
191
#else
192
0
    struct mallinfo mi1, mi2;
193
0
#endif
194
0
    void *ptr;
195
196
#ifdef HA_HAVE_MALLINFO2
197
    mi1 = mallinfo2();
198
#else
199
0
    mi1 = mallinfo();
200
0
#endif
201
0
    ptr = DISGUISE(malloc(1));
202
#ifdef HA_HAVE_MALLINFO2
203
    mi2 = mallinfo2();
204
#else
205
0
    mi2 = mallinfo();
206
0
#endif
207
0
    free(DISGUISE(ptr));
208
209
0
    using_default_allocator = !!memcmp(&mi1, &mi2, sizeof(mi1));
210
#elif defined(HA_HAVE_MALLOC_ZONE)
211
    using_default_allocator = (malloc_default_zone() != NULL);
212
#endif
213
0
  }
214
215
  /* detect presence of malloc_trim() */
216
0
  _malloc_trim = get_sym_next_addr("malloc_trim");
217
0
}
218
219
/* replace the libc's malloc_trim() so that we can also intercept the calls
220
 * from child libraries when the allocator is not the default one.
221
 */
222
int malloc_trim(size_t pad)
223
0
{
224
0
  int ret = 0;
225
226
0
  if (disable_trim)
227
0
    return ret;
228
229
0
  HA_ATOMIC_INC(&pool_trim_in_progress);
230
231
0
  if (my_mallctl) {
232
    /* here we're on jemalloc and malloc_trim() is called either
233
     * by haproxy or another dependency (the worst case that
234
     * normally crashes). Instead of just failing, we can actually
235
     * emulate it so let's do it now.
236
     */
237
0
    unsigned int i, narenas = 0;
238
0
    size_t len = sizeof(narenas);
239
240
0
    if (my_mallctl("arenas.narenas", &narenas, &len, NULL, 0) == 0) {
241
0
      for (i = 0; i < narenas; i ++) {
242
0
        char mib[32] = {0};
243
0
        snprintf(mib, sizeof(mib), "arena.%u.purge", i);
244
0
        (void)my_mallctl(mib, NULL, NULL, NULL, 0);
245
0
        ret = 1; // success
246
0
      }
247
0
    }
248
0
  }
249
0
  else if (!using_default_allocator) {
250
    /* special allocators that can be LD_PRELOADed end here */
251
0
    ret = 0; // did nothing
252
0
  }
253
0
  else if (_malloc_trim) {
254
    /* we're typically on glibc and not overridden */
255
0
    ret = _malloc_trim(pad);
256
0
  }
257
#if defined(HA_HAVE_MALLOC_ZONE)
258
  else {
259
    /* we're on MacOS, there's an equivalent mechanism */
260
    vm_address_t *zones;
261
    unsigned int i, nzones;
262
263
    if (malloc_get_all_zones(0, NULL, &zones, &nzones) == KERN_SUCCESS) {
264
      for (i = 0; i < nzones; i ++) {
265
        malloc_zone_t *zone = (malloc_zone_t *)zones[i];
266
267
        /* we cannot purge anonymous zones */
268
        if (zone->zone_name) {
269
          malloc_zone_pressure_relief(zone, 0);
270
          ret = 1; // success
271
        }
272
      }
273
    }
274
  }
275
#endif
276
0
  HA_ATOMIC_DEC(&pool_trim_in_progress);
277
278
  /* here we have ret=0 if nothing was release, or 1 if some were */
279
0
  return ret;
280
0
}
281
282
static int mem_should_fail(const struct pool_head *pool)
283
0
{
284
0
  int ret = 0;
285
286
0
  if (mem_fail_rate > 0 && !(global.mode & MODE_STARTING)) {
287
0
    if (mem_fail_rate > statistical_prng_range(100))
288
0
      ret = 1;
289
0
    else
290
0
      ret = 0;
291
0
  }
292
0
  return ret;
293
0
}
294
295
/* Try to find an existing shared pool with the same characteristics and
296
 * returns it, otherwise creates this one. NULL is returned if no memory
297
 * is available for a new creation. Two flags are supported :
298
 *   - MEM_F_SHARED to indicate that the pool may be shared with other users
299
 *   - MEM_F_EXACT to indicate that the size must not be rounded up
300
 * The name must be a stable pointer during all the program's life time.
301
 * The file and line are passed to store the registration location in the
302
 * registration struct. Use create_pool() instead which does it for free.
303
 * The alignment will be stored as-is in the registration.
304
 */
305
struct pool_head *create_pool_with_loc(const char *name, ullong size,
306
               unsigned int align, unsigned int flags,
307
               const char *file, unsigned int line)
308
4
{
309
4
  struct pool_registration *reg;
310
4
  struct pool_head *pool;
311
312
4
  reg = calloc(1, sizeof(*reg));
313
4
  if (!reg)
314
0
    return NULL;
315
316
4
  reg->name = name;
317
4
  reg->file = file;
318
4
  reg->line = line;
319
4
  reg->size = size;
320
4
  reg->flags = flags;
321
4
  reg->align = align;
322
323
4
  pool = create_pool_from_reg(name, reg);
324
4
  if (!pool)
325
0
    free(reg);
326
4
  return pool;
327
4
}
328
329
/* create a pool from a pool registration. All configuration is taken from
330
 * there. The alignment will automatically be raised to sizeof(void*) or the
331
 * next power of two so that it's always possible to lazily pass alignof() or
332
 * sizeof(). Alignments are always respected when merging pools.
333
 */
334
struct pool_head *create_pool_from_reg(const char *name, struct pool_registration *reg)
335
4
{
336
4
  unsigned int extra_mark, extra_caller, extra;
337
4
  unsigned int flags = reg->flags;
338
4
  ullong reg_size = reg->size; // copy of the originally requested size
339
4
  ullong size = reg_size;
340
4
  unsigned int alignment = reg->align;
341
4
  struct pool_head *pool = NULL;
342
4
  struct pool_head *entry;
343
4
  struct list *start;
344
4
  unsigned int align;
345
4
  unsigned int best_diff;
346
4
  int thr __maybe_unused;
347
348
  /* alignment of zero means type alignment */
349
4
  if (!alignment)
350
4
    alignment = reg->type_align;
351
352
  /* extend alignment if needed */
353
4
  if (alignment < sizeof(void*))
354
4
    alignment = sizeof(void*);
355
0
  else if (alignment & (alignment - 1)) {
356
    /* not power of two! round up to next power of two by filling
357
     * all LSB in O(log(log(N))) then increment the result.
358
     */
359
0
    int shift = 1;
360
0
    do {
361
0
      alignment |= alignment >> shift;
362
0
      shift *= 2;
363
0
    } while (alignment & (alignment + 1));
364
0
    alignment++;
365
0
  }
366
367
4
  if (reg->type_align && alignment < reg->type_align) {
368
0
    ha_alert("BUG in the code: at %s:%u, requested creation of pool '%s' aligned to %u "
369
0
       "while type requires alignment of %u! Please report to developers. Aborting.\n",
370
0
       reg->file, reg->line, name, alignment, reg->type_align);
371
0
    return NULL;
372
0
  }
373
374
4
  if (invalid_char(name)) {
375
0
    ha_alert("Pool '%s' declared at %s:%u contains invalid chars in its name and "
376
0
       "cannot be registered. Please report to developers. Aborting.\n",
377
0
       name, reg->file, reg->line);
378
0
    return NULL;
379
0
  }
380
381
4
  extra_mark = (pool_debugging & POOL_DBG_TAG) ? POOL_EXTRA_MARK : 0;
382
4
  extra_caller = (pool_debugging & POOL_DBG_CALLER) ? POOL_EXTRA_CALLER : 0;
383
4
  extra = extra_mark + extra_caller;
384
385
4
  if (size > 0xFFFFFFFFULL || (size + extra) > 0xFFFFFFFFULL || (uint)(size + extra) < (uint)reg_size)
386
0
    goto ovf;
387
388
4
  if (!(pool_debugging & POOL_DBG_NO_CACHE)) {
389
    /* we'll store two lists there, we need the room for this. Let's
390
     * make sure it's always OK even when including the extra word
391
     * that is stored after the pci struct.
392
     */
393
4
    if (size + extra - extra_caller < sizeof(struct pool_cache_item))
394
0
      size = sizeof(struct pool_cache_item) + extra_caller - extra;
395
4
  }
396
397
  /* Now we know our size is set to the strict minimum possible. It may
398
   * be OK for elements allocated with an exact size (e.g. buffers), but
399
   * we're going to round the size up 16 bytes to merge almost identical
400
   * pools together. We only round up however when we add the debugging
401
   * tag since it's used to detect overflows. Otherwise we only round up
402
   * to the size of a word to preserve alignment.
403
   */
404
4
  if (!(flags & MEM_F_EXACT)) {
405
0
    align = (pool_debugging & POOL_DBG_TAG) ? sizeof(void *) : 16;
406
0
    size  = ((size + align - 1) & -(ullong)align);
407
0
  }
408
409
4
  if (pool_debugging & POOL_DBG_BACKUP) {
410
    /* keep a full backup of the pool at release time. We need
411
     * a word-aligned size, so it's fine to do it now.
412
     */
413
0
    extra += size;
414
0
  }
415
416
4
  if (size > 0xFFFFFFFFULL || (size + extra) > 0xFFFFFFFFULL || (uint)(size + extra) < (uint)reg_size)
417
0
    goto ovf;
418
419
  /* TODO: thread: we do not lock pool list for now because all pools are
420
   * created during HAProxy startup (so before threads creation) */
421
4
  start = &pools;
422
4
  best_diff = ~0U;
423
424
4
  list_for_each_entry(entry, &pools, list) {
425
3
    if (entry->size == size ||
426
3
        (!(flags & MEM_F_EXACT) && !pool_allocated(entry) &&
427
         /* size within 1% of avg size */
428
0
         (((ullong)entry->sum_size * 100ULL < (ullong)size * entry->users * 101ULL &&
429
0
           (ullong)entry->sum_size * 101ULL > (ullong)size * entry->users * 100ULL) ||
430
          /* or +/- 16 compared to the current avg size */
431
0
          (entry->sum_size - 16 * entry->users < size * entry->users &&
432
0
           entry->sum_size + 16 * entry->users > size * entry->users)))) {
433
434
      /* either we can share this place and we take it, or
435
       * we look for a shareable one or for the next position
436
       * before which we will insert a new one.
437
       */
438
0
      if ((flags & entry->flags & MEM_F_SHARED) &&
439
0
          (!(pool_debugging & POOL_DBG_DONT_MERGE) ||
440
0
           strcmp(name, entry->name) == 0)) {
441
        /* we can share this one */
442
0
        uint diff = (abs((int)(size * entry->users - entry->size)) + entry->users / 2) / entry->users;
443
444
        /* the principle here is:
445
         *   - if the best pool is smaller and the current
446
         *     candidate larger, we prefer the larger one
447
         *     so as not to grow an existing pool;
448
         *   - otherwise we go for the smallest distance
449
         *     from the existing one.
450
         */
451
0
        if (!pool || entry->size == size ||
452
0
            (pool->size != size &&
453
0
             ((pool->size < size && entry->size >= size) ||
454
0
              (diff == best_diff && entry->size >= size) ||
455
0
              (diff < best_diff)))) {
456
0
          best_diff = diff;
457
0
          pool = entry;
458
0
        }
459
0
      }
460
0
    }
461
3
    else if (entry->size > size) {
462
      /* insert before this one */
463
2
      start = &entry->list;
464
2
    }
465
3
  }
466
467
4
  if (!pool) {
468
4
    void *pool_addr;
469
470
4
    pool_addr = calloc(1, sizeof(*pool) + __alignof__(*pool));
471
4
    if (!pool_addr)
472
0
      goto fail;
473
474
    /* always provide an aligned pool */
475
4
    pool = (struct pool_head*)((((size_t)pool_addr) + __alignof__(*pool)) & -(size_t)__alignof__(*pool));
476
4
    pool->base_addr = pool_addr; // keep it, it's the address to free later
477
478
4
    if (name)
479
4
      strlcpy2(pool->name, name, sizeof(pool->name));
480
4
    pool->alloc_sz = size + extra;
481
4
    pool->size = size;
482
4
    pool->align = alignment;
483
4
    pool->flags = flags;
484
4
    LIST_APPEND(start, &pool->list);
485
4
    LIST_INIT(&pool->regs);
486
487
4
    if (!(pool_debugging & POOL_DBG_NO_CACHE)) {
488
      /* update per-thread pool cache if necessary */
489
8
      for (thr = 0; thr < MAX_THREADS; thr++) {
490
4
        LIST_INIT(&pool->cache[thr].list);
491
4
        pool->cache[thr].tid = thr;
492
4
        pool->cache[thr].pool = pool;
493
4
      }
494
4
    }
495
4
  }
496
0
  else {
497
    /* we found the best one */
498
0
    if (size > pool->size) {
499
0
      pool->size = size;
500
0
      pool->alloc_sz = size + extra;
501
0
    }
502
0
    if (alignment > pool->align)
503
0
      pool->align = alignment;
504
0
    DPRINTF(stderr, "Sharing %s with %s\n", name, pool->name);
505
0
  }
506
507
4
  LIST_APPEND(&pool->regs, &reg->list);
508
4
  pool->users++;
509
4
  pool->sum_size += size;
510
511
4
 fail:
512
4
  return pool;
513
0
 ovf:
514
0
  ha_alert("Failed to create pool '%s' of size '%llu': overflow detected due to too large "
515
0
           "a configured size and/or configured pool options. Aborting.\n",
516
0
           name, reg_size);
517
0
  return NULL;
518
4
}
519
520
/* Tries to allocate an object for the pool <pool> using the system's allocator
521
 * and directly returns it. The pool's allocated counter is checked but NOT
522
 * updated, this is left to the caller, and but no other checks are performed.
523
 */
524
void *pool_get_from_os_noinc(struct pool_head *pool)
525
0
{
526
0
  if (!pool->limit || pool_allocated(pool) < pool->limit) {
527
0
    void *ptr;
528
529
0
    if ((pool_debugging & POOL_DBG_UAF) || (pool->flags & MEM_F_UAF))
530
0
      ptr = pool_alloc_area_uaf(pool->alloc_sz, pool->align);
531
0
    else
532
0
      ptr = pool_alloc_area(pool->alloc_sz, pool->align);
533
0
    if (ptr)
534
0
      return ptr;
535
0
    _HA_ATOMIC_INC(&pool->buckets[pool_tbucket()].failed);
536
0
  }
537
0
  activity[tid].pool_fail++;
538
0
  return NULL;
539
540
0
}
541
542
/* Releases a pool item back to the operating system but DOES NOT update
543
 * the allocation counter, it's left to the caller to do it. It may be
544
 * done before or after, it doesn't matter, the function does not use it.
545
 */
546
void pool_put_to_os_nodec(struct pool_head *pool, void *ptr)
547
0
{
548
0
  if ((pool_debugging & POOL_DBG_UAF) || (pool->flags & MEM_F_UAF))
549
0
    pool_free_area_uaf(ptr, pool->alloc_sz);
550
0
  else
551
0
    pool_free_area(ptr, pool->alloc_sz);
552
0
}
553
554
/* Tries to allocate an object for the pool <pool> using the system's allocator
555
 * and directly returns it. The pool's counters are updated but the object is
556
 * never cached, so this is usable with and without local or shared caches.
557
 */
558
void *pool_alloc_nocache(struct pool_head *pool, const void *caller)
559
0
{
560
0
  void *ptr = NULL;
561
0
  uint bucket;
562
0
  uint used;
563
564
0
  ptr = pool_get_from_os_noinc(pool);
565
0
  if (!ptr)
566
0
    return NULL;
567
568
0
  bucket = pool_pbucket(ptr);
569
570
0
  _HA_ATOMIC_INC(&pool->buckets[bucket].allocated);
571
0
  used = _HA_ATOMIC_FETCH_ADD(&pool->buckets[bucket].used, 1);
572
0
  swrate_add_scaled_opportunistic(&pool->buckets[bucket].needed_avg, POOL_AVG_SAMPLES, used, POOL_AVG_SAMPLES/4);
573
574
  /* keep track of where the element was allocated from */
575
0
  POOL_DEBUG_SET_MARK(pool, ptr);
576
0
  POOL_DEBUG_TRACE_CALLER(pool, (struct pool_cache_item *)ptr, caller);
577
0
  return ptr;
578
0
}
579
580
/* Release a pool item back to the OS and keeps the pool's counters up to date.
581
 * This is always defined even when pools are not enabled (their usage stats
582
 * are maintained).
583
 */
584
void pool_free_nocache(struct pool_head *pool, void *ptr)
585
0
{
586
0
  uint bucket = pool_pbucket(ptr);
587
0
  uint used;
588
589
0
  used = _HA_ATOMIC_SUB_FETCH(&pool->buckets[bucket].used, 1);
590
0
  _HA_ATOMIC_DEC(&pool->buckets[bucket].allocated);
591
0
  swrate_add_opportunistic(&pool->buckets[bucket].needed_avg, POOL_AVG_SAMPLES, used);
592
593
0
  pool_put_to_os_nodec(pool, ptr);
594
0
}
595
596
/* Copies the contents of <item> to the reserved area after it to have a backup.
597
 * The item part is left untouched.
598
 */
599
void pool_copy_pattern(struct pool_cache_head *pch, struct pool_cache_item *item, uint size)
600
0
{
601
0
  ulong *ptr = (ulong *)item;
602
0
  ulong extra;
603
604
0
  if (size <= sizeof(*item))
605
0
    return;
606
607
0
  extra = !!(pool_debugging & (POOL_DBG_TAG|POOL_DBG_CALLER));
608
0
  memcpy(&ptr[size/sizeof(*ptr) + extra], ptr, size);
609
0
}
610
611
/* Updates <pch>'s fill_pattern and fills the free area after <item> with it,
612
 * up to <size> bytes. The item part is left untouched.
613
 */
614
void pool_fill_pattern(struct pool_cache_head *pch, struct pool_cache_item *item, uint size)
615
0
{
616
0
  ulong *ptr = (ulong *)item;
617
0
  uint ofs;
618
0
  ulong u;
619
620
0
  if (size <= sizeof(*item))
621
0
    return;
622
623
  /* Upgrade the fill_pattern to change about half of the bits
624
   * (to be sure to catch static flag corruption), and apply it.
625
   */
626
0
  u = pch->fill_pattern += ~0UL / 3; // 0x55...55
627
0
  ofs = sizeof(*item) / sizeof(*ptr);
628
0
  while (ofs < size / sizeof(*ptr))
629
0
    ptr[ofs++] = u;
630
0
}
631
632
/* check for a pool_cache_item integrity after extracting it from the cache. It
633
 * must have been previously initialized using either pool_fill_pattern() or
634
 * pool_copy_pattern(). If any corruption is detected, the function provokes an
635
 * immediate crash.
636
 */
637
void pool_check_pattern(struct pool_cache_head *pch, struct pool_head *pool, struct pool_cache_item *item, const void *caller)
638
0
{
639
0
  const ulong *ptr = (const ulong *)item;
640
0
  uint size = pool->size;
641
0
  uint ofs;
642
0
  ulong u;
643
644
0
  if (size <= sizeof(*item))
645
0
    return;
646
647
0
  if (pool_debugging & POOL_DBG_INTEGRITY) {
648
    /* let's check that all words past *item are equal */
649
0
    ofs = sizeof(*item) / sizeof(*ptr);
650
0
    u = ptr[ofs++];
651
0
    while (ofs < size / sizeof(*ptr)) {
652
0
      if (unlikely(ptr[ofs] != u)) {
653
0
        pool_inspect_item("cache corruption detected", pool, item, caller, ofs * sizeof(*ptr));
654
0
        ABORT_NOW();
655
0
      }
656
0
      ofs++;
657
0
    }
658
0
  } else {
659
    /* the pattern was backed up */
660
0
    ofs = sizeof(*item) / sizeof(*ptr);
661
0
    u = !!(pool_debugging & (POOL_DBG_TAG|POOL_DBG_CALLER));
662
0
    while (ofs < size / sizeof(*ptr)) {
663
0
      if (unlikely(ptr[ofs] != ptr[size/sizeof(*ptr) + u + ofs])) {
664
0
        pool_inspect_item("cache corruption detected", pool, item, caller, ofs * sizeof(*ptr));
665
0
        ABORT_NOW();
666
0
      }
667
0
      ofs++;
668
0
    }
669
0
  }
670
0
}
671
672
/* removes up to <count> items from the end of the local pool cache <ph> for
673
 * pool <pool>. The shared pool is refilled with these objects in the limit
674
 * of the number of acceptable objects, and the rest will be released to the
675
 * OS. It is not a problem is <count> is larger than the number of objects in
676
 * the local cache. The counters are automatically updated. Must not be used
677
 * with pools disabled.
678
 */
679
static void pool_evict_last_items(struct pool_head *pool, struct pool_cache_head *ph, uint count)
680
0
{
681
0
  struct pool_cache_item *item;
682
0
  struct pool_item *pi, *head = NULL;
683
0
  void *caller = __builtin_return_address(0);
684
0
  uint released = 0;
685
0
  uint cluster = 0;
686
0
  uint to_free_max;
687
0
  uint bucket;
688
0
  uint used;
689
690
0
  BUG_ON(pool_debugging & POOL_DBG_NO_CACHE);
691
692
  /* Note: this will be zero when global pools are disabled */
693
0
  to_free_max = pool_releasable(pool);
694
695
0
  while (released < count && !LIST_ISEMPTY(&ph->list)) {
696
0
    item = LIST_PREV(&ph->list, typeof(item), by_pool);
697
0
    BUG_ON(&item->by_pool == &ph->list);
698
0
    if (unlikely(pool_debugging & (POOL_DBG_INTEGRITY|POOL_DBG_BACKUP)))
699
0
      pool_check_pattern(ph, pool, item, caller);
700
0
    LIST_DELETE(&item->by_pool);
701
0
    LIST_DELETE(&item->by_lru);
702
703
0
    bucket = pool_pbucket(item);
704
0
    used = _HA_ATOMIC_SUB_FETCH(&pool->buckets[bucket].used, 1);
705
0
    swrate_add_opportunistic(&pool->buckets[bucket].needed_avg, POOL_AVG_SAMPLES, used);
706
707
0
    if (to_free_max > released || cluster) {
708
      /* will never match when global pools are disabled */
709
0
      pi = (struct pool_item *)item;
710
0
      pi->next = NULL;
711
0
      pi->down = head;
712
0
      head = pi;
713
0
      cluster++;
714
0
      if (cluster >= CONFIG_HAP_POOL_CLUSTER_SIZE) {
715
        /* enough to make a cluster */
716
0
        pool_put_to_shared_cache(pool, head);
717
0
        cluster = 0;
718
0
        head = NULL;
719
0
      }
720
0
    } else {
721
      /* does pool_free_nocache() with a known bucket */
722
0
      _HA_ATOMIC_DEC(&pool->buckets[bucket].allocated);
723
0
      pool_put_to_os_nodec(pool, item);
724
0
    }
725
726
0
    released++;
727
0
  }
728
729
  /* incomplete cluster left */
730
0
  if (cluster)
731
0
    pool_put_to_shared_cache(pool, head);
732
733
0
  ph->count -= released;
734
0
  pool_cache_count -= released;
735
0
  pool_cache_bytes -= released * pool->size;
736
0
}
737
738
/* Evicts some of the oldest objects from one local cache, until its number of
739
 * objects is no more than 16+1/8 of the total number of locally cached objects
740
 * or the total size of the local cache is no more than 75% of its maximum (i.e.
741
 * we don't want a single cache to use all the cache for itself). For this, the
742
 * list is scanned in reverse. If <full> is non-null, all objects are evicted.
743
 * Must not be used when pools are disabled.
744
 */
745
void pool_evict_from_local_cache(struct pool_head *pool, int full)
746
2
{
747
2
  struct pool_cache_head *ph = &pool->cache[tid];
748
749
2
  BUG_ON(pool_debugging & POOL_DBG_NO_CACHE);
750
751
2
  while ((ph->count && full) ||
752
2
         (ph->count >= CONFIG_HAP_POOL_CLUSTER_SIZE &&
753
0
          ph->count >= 16 + pool_cache_count / 8 &&
754
0
          pool_cache_bytes > global.tune.pool_cache_size * 3 / 4)) {
755
0
    pool_evict_last_items(pool, ph, CONFIG_HAP_POOL_CLUSTER_SIZE);
756
0
  }
757
2
}
758
759
/* Evicts some of the oldest objects from the local cache, pushing them to the
760
 * global pool. Must not be used when pools are disabled.
761
 */
762
void pool_evict_from_local_caches()
763
0
{
764
0
  struct pool_cache_item *item;
765
0
  struct pool_cache_head *ph;
766
0
  struct pool_head *pool;
767
768
0
  BUG_ON(pool_debugging & POOL_DBG_NO_CACHE);
769
770
0
  do {
771
0
    item = LIST_PREV(&th_ctx->pool_lru_head, struct pool_cache_item *, by_lru);
772
0
    BUG_ON(&item->by_lru == &th_ctx->pool_lru_head);
773
    /* note: by definition we remove oldest objects so they also are the
774
     * oldest in their own pools, thus their next is the pool's head.
775
     */
776
0
    ph = LIST_NEXT(&item->by_pool, struct pool_cache_head *, list);
777
0
    BUG_ON(ph->tid != tid);
778
779
0
    pool = container_of(ph - tid, struct pool_head, cache);
780
0
    BUG_ON(pool != ph->pool);
781
782
0
    pool_evict_last_items(pool, ph, CONFIG_HAP_POOL_CLUSTER_SIZE);
783
0
  } while (pool_cache_bytes > global.tune.pool_cache_size * 7 / 8);
784
0
}
785
786
/* Frees an object to the local cache, possibly pushing oldest objects to the
787
 * shared cache, which itself may decide to release some of them to the OS.
788
 * While it is unspecified what the object becomes past this point, it is
789
 * guaranteed to be released from the users' perspective. A caller address may
790
 * be passed and stored into the area when DEBUG_POOL_TRACING is set. Must not
791
 * be used with pools disabled.
792
 */
793
void pool_put_to_cache(struct pool_head *pool, void *ptr, const void *caller)
794
0
{
795
0
  struct pool_cache_item *item = (struct pool_cache_item *)ptr;
796
0
  struct pool_cache_head *ph = &pool->cache[tid];
797
798
0
  BUG_ON(pool_debugging & POOL_DBG_NO_CACHE);
799
800
0
  LIST_INSERT(&ph->list, &item->by_pool);
801
0
  LIST_INSERT(&th_ctx->pool_lru_head, &item->by_lru);
802
0
  POOL_DEBUG_TRACE_CALLER(pool, item, caller);
803
0
  ph->count++;
804
0
  if (unlikely(pool_debugging & POOL_DBG_BACKUP))
805
0
    pool_copy_pattern(ph, item, pool->size);
806
807
0
  if (unlikely(pool_debugging & POOL_DBG_INTEGRITY))
808
0
    pool_fill_pattern(ph, item, pool->size);
809
810
0
  pool_cache_count++;
811
0
  pool_cache_bytes += pool->size;
812
813
0
  if (unlikely(pool_cache_bytes > global.tune.pool_cache_size * 3 / 4)) {
814
0
    uint64_t mem_wait_start = 0;
815
816
0
    if (unlikely((th_ctx->flags & (TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_M)) ==
817
0
                 (TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_M)))
818
0
      mem_wait_start = now_mono_time();
819
820
0
    if (ph->count >= 16 + pool_cache_count / 8 + CONFIG_HAP_POOL_CLUSTER_SIZE)
821
0
      pool_evict_from_local_cache(pool, 0);
822
0
    if (pool_cache_bytes > global.tune.pool_cache_size)
823
0
      pool_evict_from_local_caches();
824
825
0
    if (unlikely(mem_wait_start))
826
0
      th_ctx->mem_wait_total += now_mono_time() - mem_wait_start;
827
0
  }
828
0
}
829
830
/* Tries to refill the local cache <pch> from the shared one for pool <pool>.
831
 * This is only used when pools are in use and shared pools are enabled. No
832
 * malloc() is attempted, and poisonning is never performed. The purpose is to
833
 * get the fastest possible refilling so that the caller can easily check if
834
 * the cache has enough objects for its use. Must not be used when pools are
835
 * disabled.
836
 */
837
void pool_refill_local_from_shared(struct pool_head *pool, struct pool_cache_head *pch)
838
0
{
839
0
  struct pool_cache_item *item;
840
0
  struct pool_item *ret, *down;
841
0
  uint bucket;
842
0
  uint count;
843
844
0
  BUG_ON(pool_debugging & POOL_DBG_NO_CACHE);
845
846
  /* we'll need to reference the first element to figure the next one. We
847
   * must temporarily lock it so that nobody allocates then releases it,
848
   * or the dereference could fail. In order to limit the locking,
849
   * threads start from a bucket that depends on their ID.
850
   */
851
852
0
  bucket = pool_tbucket();
853
0
  ret = _HA_ATOMIC_LOAD(&pool->buckets[bucket].free_list);
854
0
  count = 0;
855
0
  do {
856
    /* look for an apparently non-busy entry. If we hit a busy pool
857
     * we retry with another random bucket. And if we encounter a
858
     * NULL, we retry once with another random bucket. This is in
859
     * order to prevent object accumulation in other buckets.
860
     */
861
0
    while (unlikely(ret == POOL_BUSY || (ret == NULL && count++ < 1))) {
862
0
      bucket = statistical_prng() % CONFIG_HAP_POOL_BUCKETS;
863
0
      ret = _HA_ATOMIC_LOAD(&pool->buckets[bucket].free_list);
864
0
    }
865
0
    if (ret == NULL)
866
0
      return;
867
0
  } while (unlikely((ret = _HA_ATOMIC_XCHG(&pool->buckets[bucket].free_list, POOL_BUSY)) == POOL_BUSY));
868
869
0
  if (unlikely(ret == NULL)) {
870
0
    HA_ATOMIC_STORE(&pool->buckets[bucket].free_list, NULL);
871
0
    return;
872
0
  }
873
874
  /* this releases the lock */
875
0
  HA_ATOMIC_STORE(&pool->buckets[bucket].free_list, ret->next);
876
877
  /* now store the retrieved object(s) into the local cache. Note that
878
   * they don't all have the same hash and that it doesn't necessarily
879
   * match the one from the pool.
880
   */
881
0
  count = 0;
882
0
  for (; ret; ret = down) {
883
0
    down = ret->down;
884
0
    item = (struct pool_cache_item *)ret;
885
0
    POOL_DEBUG_TRACE_CALLER(pool, item, NULL);
886
0
    LIST_INSERT(&pch->list, &item->by_pool);
887
0
    LIST_INSERT(&th_ctx->pool_lru_head, &item->by_lru);
888
0
    _HA_ATOMIC_INC(&pool->buckets[pool_pbucket(item)].used);
889
0
    count++;
890
0
    if (unlikely(pool_debugging & POOL_DBG_INTEGRITY))
891
0
      pool_fill_pattern(pch, item, pool->size);
892
893
0
  }
894
0
  pch->count += count;
895
0
  pool_cache_count += count;
896
0
  pool_cache_bytes += count * pool->size;
897
0
}
898
899
/* Adds pool item cluster <item> to the shared cache, which contains <count>
900
 * elements. The caller is advised to first check using pool_releasable() if
901
 * it's wise to add this series of objects there. Both the pool and the item's
902
 * head must be valid.
903
 */
904
void pool_put_to_shared_cache(struct pool_head *pool, struct pool_item *item)
905
0
{
906
0
  struct pool_item *free_list;
907
0
  uint bucket = pool_pbucket(item);
908
909
  /* we prefer to put the item into the entry that corresponds to its own
910
   * hash so that on return it remains in the right place, but that's not
911
   * mandatory.
912
   */
913
0
  free_list = _HA_ATOMIC_LOAD(&pool->buckets[bucket].free_list);
914
0
  do {
915
    /* look for an apparently non-busy entry */
916
0
    while (unlikely(free_list == POOL_BUSY)) {
917
0
      bucket = (bucket + 1) % CONFIG_HAP_POOL_BUCKETS;
918
0
      free_list = _HA_ATOMIC_LOAD(&pool->buckets[bucket].free_list);
919
0
    }
920
0
    _HA_ATOMIC_STORE(&item->next, free_list);
921
0
    __ha_barrier_atomic_store();
922
0
  } while (!_HA_ATOMIC_CAS(&pool->buckets[bucket].free_list, &free_list, item));
923
0
  __ha_barrier_atomic_store();
924
0
}
925
926
/*
927
 * This function frees whatever can be freed in pool <pool>.
928
 */
929
void pool_flush(struct pool_head *pool)
930
2
{
931
2
  struct pool_item *next, *temp, *down;
932
2
  uint bucket;
933
934
2
  if (!pool || (pool_debugging & (POOL_DBG_NO_CACHE|POOL_DBG_NO_GLOBAL)))
935
0
    return;
936
937
  /* The loop below atomically detaches the head of the free list and
938
   * replaces it with a NULL. Then the list can be released.
939
   */
940
4
  for (bucket = 0; bucket < CONFIG_HAP_POOL_BUCKETS; bucket++) {
941
2
    next = pool->buckets[bucket].free_list;
942
2
    while (1) {
943
2
      while (unlikely(next == POOL_BUSY))
944
0
        next = (void*)pl_wait_new_long((ulong*)&pool->buckets[bucket].free_list, (ulong)next);
945
946
2
      if (next == NULL)
947
2
        break;
948
949
0
      next = _HA_ATOMIC_XCHG(&pool->buckets[bucket].free_list, POOL_BUSY);
950
0
      if (next != POOL_BUSY) {
951
0
        HA_ATOMIC_STORE(&pool->buckets[bucket].free_list, NULL);
952
0
        break;
953
0
      }
954
0
    }
955
956
2
    while (next) {
957
0
      temp = next;
958
0
      next = temp->next;
959
0
      for (; temp; temp = down) {
960
0
        down = temp->down;
961
0
        _HA_ATOMIC_DEC(&pool->buckets[pool_pbucket(temp)].allocated);
962
0
        pool_put_to_os_nodec(pool, temp);
963
0
      }
964
0
    }
965
2
  }
966
  /* here, we should have pool->allocated == pool->used */
967
2
}
968
969
/*
970
 * This function frees whatever can be freed in all pools, but respecting
971
 * the minimum thresholds imposed by owners. It makes sure to be alone to
972
 * run by using thread_isolate(). <pool_ctx> is unused.
973
 */
974
void pool_gc(struct pool_head *pool_ctx)
975
0
{
976
0
  struct pool_head *entry;
977
0
  uint64_t mem_wait_start = 0;
978
0
  int isolated = thread_isolated();
979
980
0
  if (unlikely((th_ctx->flags & (TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_M)) ==
981
0
               (TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_M)))
982
0
    mem_wait_start = now_mono_time();
983
984
0
  if (!isolated)
985
0
    thread_isolate();
986
987
0
  list_for_each_entry(entry, &pools, list) {
988
0
    struct pool_item *temp, *down;
989
0
    uint allocated = pool_allocated(entry);
990
0
    uint used = pool_used(entry);
991
0
    int bucket = 0;
992
993
0
    while ((int)(allocated - used) > (int)entry->minavail) {
994
      /* ok let's find next entry to evict */
995
0
      while (!entry->buckets[bucket].free_list && bucket < CONFIG_HAP_POOL_BUCKETS)
996
0
        bucket++;
997
998
0
      if (bucket >= CONFIG_HAP_POOL_BUCKETS)
999
0
        break;
1000
1001
0
      temp = entry->buckets[bucket].free_list;
1002
0
      entry->buckets[bucket].free_list = temp->next;
1003
0
      for (; temp; temp = down) {
1004
0
        down = temp->down;
1005
0
        allocated--;
1006
0
        _HA_ATOMIC_DEC(&entry->buckets[pool_pbucket(temp)].allocated);
1007
0
        pool_put_to_os_nodec(entry, temp);
1008
0
      }
1009
0
    }
1010
0
  }
1011
1012
0
  trim_all_pools();
1013
1014
0
  if (!isolated)
1015
0
    thread_release();
1016
1017
0
  if (mem_wait_start)
1018
0
    th_ctx->mem_wait_total += now_mono_time() - mem_wait_start;
1019
0
}
1020
1021
/*
1022
 * Returns a pointer to type <type> taken from the pool <pool_type> or
1023
 * dynamically allocated. In the first case, <pool_type> is updated to point to
1024
 * the next element in the list. <flags> is a binary-OR of POOL_F_* flags.
1025
 * Prefer using pool_alloc() which does the right thing without flags.
1026
 */
1027
void *__pool_alloc(struct pool_head *pool, unsigned int flags)
1028
0
{
1029
0
  void *p = NULL;
1030
0
  void *caller = __builtin_return_address(0);
1031
1032
0
  if (unlikely(pool_debugging & POOL_DBG_FAIL_ALLOC))
1033
0
    if (!(flags & POOL_F_NO_FAIL) && mem_should_fail(pool))
1034
0
      return NULL;
1035
1036
0
  if (likely(!(pool_debugging & POOL_DBG_NO_CACHE)) && !p)
1037
0
    p = pool_get_from_cache(pool, caller);
1038
1039
0
  if (unlikely(!p)) {
1040
    /* count allocation time only for cache misses */
1041
0
    uint64_t mem_wait_start = 0;
1042
1043
0
    if (unlikely((th_ctx->flags & (TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_M)) ==
1044
0
                       (TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_M)))
1045
0
      mem_wait_start = now_mono_time();
1046
1047
0
    p = pool_alloc_nocache(pool, caller);
1048
1049
0
    if (unlikely(mem_wait_start))
1050
0
      th_ctx->mem_wait_total += now_mono_time() - mem_wait_start;
1051
0
  }
1052
1053
0
  if (likely(p)) {
1054
#ifdef USE_MEMORY_PROFILING
1055
    if (unlikely(profiling & HA_PROF_MEMORY)) {
1056
      extern struct memprof_stats memprof_stats[MEMPROF_HASH_BUCKETS + 1];
1057
      struct memprof_stats *bin;
1058
1059
      bin = memprof_get_bin(__builtin_return_address(0), MEMPROF_METH_P_ALLOC);
1060
      if (unlikely(th_ctx->lock_level & 0x7F))
1061
        _HA_ATOMIC_ADD(&bin->locked_calls, 1);
1062
      _HA_ATOMIC_ADD(&bin->alloc_calls, 1);
1063
      _HA_ATOMIC_ADD(&bin->alloc_tot, pool->size);
1064
      _HA_ATOMIC_STORE(&bin->info, pool);
1065
      /* replace the caller with the allocated bin: this way
1066
       * we'll the pool_free() call will be able to update our
1067
       * entry. We only do it for non-colliding entries though,
1068
       * since these ones store the true caller location.
1069
       */
1070
      if (bin >= &memprof_stats[0] && bin < &memprof_stats[MEMPROF_HASH_BUCKETS])
1071
        POOL_DEBUG_TRACE_CALLER(pool, (struct pool_cache_item *)p, bin);
1072
    }
1073
#endif
1074
0
    if (unlikely(flags & POOL_F_MUST_ZERO))
1075
0
      memset(p, 0, pool->size);
1076
0
    else if (unlikely(!(flags & POOL_F_NO_POISON) && (pool_debugging & POOL_DBG_POISON)))
1077
0
      memset(p, mem_poison_byte, pool->size);
1078
0
  }
1079
0
  return p;
1080
0
}
1081
1082
/*
1083
 * Puts a memory area back to the corresponding pool. <ptr> be valid. Using
1084
 * pool_free() is preferred.
1085
 */
1086
void __pool_free(struct pool_head *pool, void *ptr)
1087
0
{
1088
0
  const void *caller = __builtin_return_address(0);
1089
1090
  /* we'll get late corruption if we refill to the wrong pool or double-free */
1091
0
  POOL_DEBUG_CHECK_MARK(pool, ptr, caller);
1092
0
  POOL_DEBUG_RESET_MARK(pool, ptr);
1093
1094
#ifdef USE_MEMORY_PROFILING
1095
  if (unlikely(profiling & HA_PROF_MEMORY) && ptr) {
1096
    extern struct memprof_stats memprof_stats[MEMPROF_HASH_BUCKETS + 1];
1097
    struct memprof_stats *bin;
1098
1099
    bin = memprof_get_bin(__builtin_return_address(0), MEMPROF_METH_P_FREE);
1100
    if (unlikely(th_ctx->lock_level & 0x7F))
1101
      _HA_ATOMIC_ADD(&bin->locked_calls, 1);
1102
    _HA_ATOMIC_ADD(&bin->free_calls, 1);
1103
    _HA_ATOMIC_ADD(&bin->free_tot, pool->size);
1104
    _HA_ATOMIC_STORE(&bin->info, pool);
1105
1106
    /* check if the caller is an allocator, and if so, let's update
1107
     * its free() count.
1108
     */
1109
    bin = *(struct memprof_stats**)(((char *)ptr) + pool->alloc_sz - sizeof(void*));
1110
    if (bin >= &memprof_stats[0] && bin < &memprof_stats[MEMPROF_HASH_BUCKETS]) {
1111
      _HA_ATOMIC_ADD(&bin->free_calls, 1);
1112
      _HA_ATOMIC_ADD(&bin->free_tot, pool->size);
1113
    }
1114
  }
1115
#endif
1116
1117
0
  if (unlikely((pool_debugging & POOL_DBG_NO_CACHE) ||
1118
0
               (pool->flags & MEM_F_UAF) ||
1119
0
         global.tune.pool_cache_size < pool->size)) {
1120
0
    uint64_t mem_wait_start = 0;
1121
1122
0
    if (unlikely((th_ctx->flags & (TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_M)) ==
1123
0
                       (TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_M)))
1124
0
      mem_wait_start = now_mono_time();
1125
1126
0
    pool_free_nocache(pool, ptr);
1127
1128
0
    if (unlikely(mem_wait_start))
1129
0
      th_ctx->mem_wait_total += now_mono_time() - mem_wait_start;
1130
0
  }
1131
0
  else {
1132
    /* this one will count its own time itself */
1133
0
    pool_put_to_cache(pool, ptr, caller);
1134
0
  }
1135
0
}
1136
1137
/*
1138
 * This function destroys a pool by freeing it completely, unless it's still
1139
 * in use. This should be called only under extreme circumstances. It always
1140
 * returns NULL if the resulting pool is empty, easing the clearing of the old
1141
 * pointer, otherwise it returns the pool.
1142
 * .
1143
 */
1144
void *pool_destroy(struct pool_head *pool)
1145
2
{
1146
2
  if (pool) {
1147
1
    if (!(pool_debugging & POOL_DBG_NO_CACHE))
1148
1
      pool_evict_from_local_cache(pool, 1);
1149
1150
1
    pool_flush(pool);
1151
1
    if (pool_used(pool))
1152
0
      return pool;
1153
1
    pool->users--;
1154
1
    if (!pool->users) {
1155
      /* remove all registrations at once */
1156
1
      struct pool_registration *reg, *back;
1157
1158
1
      list_for_each_entry_safe(reg, back, &pool->regs, list) {
1159
1
        LIST_DELETE(&reg->list);
1160
1
        if (!(reg->flags & MEM_F_STATREG))
1161
1
          free(reg);
1162
1
      }
1163
1164
1
      LIST_DELETE(&pool->list);
1165
1166
      /* note that if used == 0, the cache is empty */
1167
1
      free(pool->base_addr);
1168
1
    }
1169
1170
    /* make sure this pool is no longer referenced in memory profiling */
1171
1
    memprof_remove_stale_info(pool);
1172
1
  }
1173
2
  return NULL;
1174
2
}
1175
1176
/* This destroys all pools on exit. It is *not* thread safe. */
1177
void pool_destroy_all()
1178
0
{
1179
0
  struct pool_head *entry, *back;
1180
1181
0
  list_for_each_entry_safe(entry, back, &pools, list) {
1182
    /* there's only one occurrence of each pool in the list,
1183
     * and we're existing instead of looping on the whole
1184
     * list just to decrement users, force it to 1 here.
1185
     */
1186
0
    entry->users = 1;
1187
0
    pool_destroy(entry);
1188
0
  }
1189
0
}
1190
1191
/* carefully inspects an item upon fatal error and emit diagnostics.
1192
 * If ofs < 0, no hint is provided regarding the content location. However if
1193
 * ofs >= 0, then we also try to inspect around that place where corruption
1194
 * was detected.
1195
 */
1196
void pool_inspect_item(const char *msg, struct pool_head *pool, const void *item, const void *caller, ssize_t ofs)
1197
0
{
1198
0
  const struct pool_head *the_pool = NULL;
1199
1200
0
  chunk_printf(&trash,
1201
0
         "FATAL: pool inconsistency detected in thread %d: %s.\n"
1202
0
         "  caller: %p (",
1203
0
         tid + 1, msg, caller);
1204
1205
0
  resolve_sym_name(&trash, NULL, caller);
1206
1207
0
  chunk_appendf(&trash,
1208
0
          ")\n"
1209
0
          "  item: %p\n"
1210
0
          "  pool: %p ('%s', size %u, real %u, users %u)\n",
1211
0
          item, pool, pool->name, pool->size, pool->alloc_sz, pool->users);
1212
1213
0
  if (ofs >= 0) {
1214
0
    chunk_printf(&trash, "Contents around first corrupted address relative to pool item:.\n");
1215
0
    dump_area_with_syms(&trash, item, item + ofs, NULL, NULL, NULL);
1216
0
  }
1217
1218
0
  if (pool_debugging & POOL_DBG_TAG) {
1219
0
    const void **pool_mark;
1220
0
    struct pool_head *ph;
1221
0
    const void *tag;
1222
1223
0
    pool_mark = (const void **)(((char *)item) + pool->size);
1224
0
    tag =  may_access(pool_mark) ? *pool_mark : NULL;
1225
0
    if (tag == pool) {
1226
0
      chunk_appendf(&trash, "  tag: @%p = %p (%s)\n", pool_mark, tag, pool->name);
1227
0
      the_pool = pool;
1228
0
    }
1229
0
    else {
1230
0
      if (!may_access(pool_mark))
1231
0
        chunk_appendf(&trash, "Tag not accessible. ");
1232
0
      else
1233
0
        chunk_appendf(&trash, "Tag does not match (%p). ", tag);
1234
1235
0
      list_for_each_entry(ph, &pools, list) {
1236
0
        pool_mark = (const void **)(((char *)item) + ph->size);
1237
0
        if (!may_access(pool_mark))
1238
0
          continue;
1239
0
        tag =  *pool_mark;
1240
1241
0
        if (tag == ph) {
1242
0
          if (!the_pool)
1243
0
            chunk_appendf(&trash, "Possible origin pool(s):\n");
1244
1245
0
          chunk_appendf(&trash, "  tag: @%p = %p (%s, size %u, real %u, users %u)\n",
1246
0
                  pool_mark, tag, ph->name, ph->size, ph->alloc_sz, ph->users);
1247
0
          if (!the_pool || the_pool->size < ph->size)
1248
0
            the_pool = ph;
1249
0
        }
1250
0
      }
1251
1252
0
      if (!the_pool) {
1253
0
        chunk_appendf(&trash,
1254
0
                "Tag does not match any other pool.\n");
1255
1256
0
        pool_mark = (const void **)(((char *)item) + pool->size);
1257
0
        if (resolve_sym_name(&trash, "Resolving the tag as a pool_free() location: ", *pool_mark))
1258
0
          chunk_appendf(&trash, "\n");
1259
0
        else
1260
0
          chunk_appendf(&trash, " (no match).\n");
1261
1262
0
        dump_area_with_syms(&trash, item, pool_mark, pool, "pool", pool->name);
1263
0
      }
1264
0
    }
1265
0
  }
1266
1267
0
  if (pool_debugging & POOL_DBG_CALLER) {
1268
0
    struct buffer *trash2 = get_trash_chunk();
1269
0
    const struct pool_head *ph;
1270
0
    const void **pool_mark;
1271
0
    const void *tag, *rec_tag;
1272
1273
0
    ph = the_pool ? the_pool : pool;
1274
0
    pool_mark = (const void **)(((char *)item) + ph->alloc_sz - sizeof(void*));
1275
0
    rec_tag =  may_access(pool_mark) ? *pool_mark : NULL;
1276
1277
0
    if (rec_tag && resolve_sym_name(trash2, NULL, rec_tag))
1278
0
      chunk_appendf(&trash,
1279
0
              "Recorded caller if pool '%s':\n  @%p (+%04u) = %p (%s)\n",
1280
0
              ph->name, pool_mark, (uint)(ph->alloc_sz - sizeof(void*)),
1281
0
              rec_tag, trash2->area);
1282
1283
0
    if (!the_pool) {
1284
      /* the pool couldn't be formally verified */
1285
0
      chunk_appendf(&trash, "Other possible callers:\n");
1286
0
      list_for_each_entry(ph, &pools, list) {
1287
0
        if (ph == pool)
1288
0
          continue;
1289
0
        pool_mark = (const void **)(((char *)item) + ph->alloc_sz - sizeof(void*));
1290
0
        if (!may_access(pool_mark))
1291
0
          continue;
1292
0
        tag = *pool_mark;
1293
0
        if (tag == rec_tag)
1294
0
          continue;
1295
1296
        /* see if we can resolve something */
1297
0
        chunk_printf(trash2, "@%p (+%04u) = %p (", pool_mark, (uint)(ph->alloc_sz - sizeof(void*)), tag);
1298
0
        if (resolve_sym_name(trash2, NULL, tag)) {
1299
0
          chunk_appendf(trash2, ")");
1300
0
          chunk_appendf(&trash,
1301
0
                  "  %s [as pool %s, size %u, real %u, users %u]\n",
1302
0
                  trash2->area, ph->name, ph->size, ph->alloc_sz, ph->users);
1303
0
        }
1304
0
      }
1305
0
    }
1306
0
  }
1307
1308
0
  chunk_appendf(&trash, "\n");
1309
0
  DISGUISE(write(2, trash.area, trash.data));
1310
0
}
1311
1312
/* used by qsort in "show pools" to sort by name */
1313
static int cmp_dump_pools_name(const void *a, const void *b)
1314
0
{
1315
0
  const struct pool_dump_info *l = (const struct pool_dump_info *)a;
1316
0
  const struct pool_dump_info *r = (const struct pool_dump_info *)b;
1317
1318
0
  return strcmp(l->entry->name, r->entry->name);
1319
0
}
1320
1321
/* used by qsort in "show pools" to sort by item size */
1322
static int cmp_dump_pools_size(const void *a, const void *b)
1323
0
{
1324
0
  const struct pool_dump_info *l = (const struct pool_dump_info *)a;
1325
0
  const struct pool_dump_info *r = (const struct pool_dump_info *)b;
1326
1327
0
  if (l->entry->size > r->entry->size)
1328
0
    return -1;
1329
0
  else if (l->entry->size < r->entry->size)
1330
0
    return 1;
1331
0
  else
1332
0
    return 0;
1333
0
}
1334
1335
/* used by qsort in "show pools" to sort by usage */
1336
static int cmp_dump_pools_usage(const void *a, const void *b)
1337
0
{
1338
0
  const struct pool_dump_info *l = (const struct pool_dump_info *)a;
1339
0
  const struct pool_dump_info *r = (const struct pool_dump_info *)b;
1340
1341
0
  if (l->alloc_bytes > r->alloc_bytes)
1342
0
    return -1;
1343
0
  else if (l->alloc_bytes < r->alloc_bytes)
1344
0
    return 1;
1345
0
  else
1346
0
    return 0;
1347
0
}
1348
1349
/* This function fills the show_pools_ctx context by looping on pools. It will
1350
 * count the number of pools and allocate the array to store info about each
1351
 * pool. It returns 0 on success and -1 on error.
1352
 *
1353
 * It may sort pools by a criterion if bits 0..3 of <ctx->how> are non-zero, and
1354
 * limit the number of output lines if <ctx->maxcnt> is non-zero. It may limit
1355
 * only to pools whose names start with <ctx->prefix> if not null.
1356
 */
1357
static int get_show_pools_info(struct show_pools_ctx *ctx)
1358
0
{
1359
0
  struct pool_head *entry;
1360
0
  int by_what = (ctx->how & 0xF); // bits 0..3 = sorting criterion
1361
0
  int n = 0;
1362
1363
0
  ctx->nbpools = 0;
1364
0
  list_for_each_entry(entry, &pools, list)
1365
0
    ctx->nbpools++;
1366
1367
0
  ctx->pool_info = calloc(ctx->nbpools, sizeof(*ctx->pool_info));
1368
0
  if (ctx->pool_info == NULL)
1369
0
    return -1;
1370
1371
0
  list_for_each_entry(entry, &pools, list) {
1372
0
    uint cached = 0;
1373
0
    uint alloc_items;
1374
1375
0
    alloc_items = pool_allocated(entry);
1376
    /* do not dump unused entries when sorting by usage */
1377
0
    if (by_what == 3 && !alloc_items)
1378
0
      continue;
1379
1380
    /* verify the pool name if a prefix is requested */
1381
0
    if (ctx->prefix && strncmp(entry->name, ctx->prefix, strlen(ctx->prefix)) != 0)
1382
0
      continue;
1383
1384
0
    if (!(pool_debugging & POOL_DBG_NO_CACHE)) {
1385
0
      int i;
1386
1387
0
      for (i = 0; i < global.nbthread; i++)
1388
0
        cached += entry->cache[i].count;
1389
0
    }
1390
0
    ctx->pool_info[n].entry = entry;
1391
0
    ctx->pool_info[n].alloc_items = alloc_items;
1392
0
    ctx->pool_info[n].alloc_bytes = (ulong)entry->size * alloc_items;
1393
0
    ctx->pool_info[n].used_items = pool_used(entry);
1394
0
    ctx->pool_info[n].cached_items = cached;
1395
0
    ctx->pool_info[n].need_avg = swrate_avg(pool_needed_avg(entry), POOL_AVG_SAMPLES);
1396
0
    ctx->pool_info[n].failed_items = pool_failed(entry);
1397
1398
0
    ctx->cached_bytes += ctx->pool_info[n].cached_items * (ulong)ctx->pool_info[n].entry->size;
1399
0
    ctx->allocated    += ctx->pool_info[n].alloc_items  * (ulong)ctx->pool_info[n].entry->size;
1400
0
    ctx->used         += ctx->pool_info[n].used_items   * (ulong)ctx->pool_info[n].entry->size;
1401
0
    n++;
1402
0
  }
1403
1404
  /* adjust the number of entries to be dumped */
1405
0
  ctx->nbpools = n;
1406
1407
0
  if (by_what == 1)  /* sort by name */
1408
0
    qsort(ctx->pool_info, ctx->nbpools, sizeof(*ctx->pool_info), cmp_dump_pools_name);
1409
0
  else if (by_what == 2)  /* sort by item size */
1410
0
    qsort(ctx->pool_info, ctx->nbpools, sizeof(*ctx->pool_info), cmp_dump_pools_size);
1411
0
  else if (by_what == 3)  /* sort by total usage */
1412
0
    qsort(ctx->pool_info, ctx->nbpools, sizeof(*ctx->pool_info), cmp_dump_pools_usage);
1413
1414
0
  if (!ctx->maxcnt || ctx->maxcnt > ctx->nbpools)
1415
0
    ctx->maxcnt = ctx->nbpools;
1416
0
  ctx->pool_idx = -1;
1417
0
  return 0;
1418
0
}
1419
1420
/* This function dumps information about pools found in the applet context.
1421
 */
1422
int dump_pools_info(struct appctx *appctx)
1423
0
{
1424
0
  struct show_pools_ctx *ctx = appctx->svcctx;
1425
0
  int i;
1426
1427
0
  if (ctx->pool_idx == -1) {
1428
0
    chunk_printf(&trash, "Dumping pools usage");
1429
0
    if (ctx->nbpools > ctx->maxcnt)
1430
0
      chunk_appendf(&trash, " (limited to the first %u entries)", ctx->maxcnt);
1431
0
    chunk_appendf(&trash, ". Use SIGQUIT to flush them.\n");
1432
1433
0
    if (applet_putchk(appctx, &trash) == -1)
1434
0
      return 0;
1435
1436
0
    ctx->pool_idx = 0;
1437
0
  }
1438
1439
0
  for (i = ctx->pool_idx; i < ctx->nbpools && i < ctx->maxcnt; i++) {
1440
0
    chunk_printf(&trash, "  - Pool %s (%u bytes/%u) : %lu allocated (%lu bytes), %lu used"
1441
0
           " (~%lu by thread caches)"
1442
0
           ", needed_avg %lu, %lu failures, %u users, @%p%s\n",
1443
0
           ctx->pool_info[i].entry->name, ctx->pool_info[i].entry->size, ctx->pool_info[i].entry->align,
1444
0
           ctx->pool_info[i].alloc_items, ctx->pool_info[i].alloc_bytes,
1445
0
           ctx->pool_info[i].used_items, ctx->pool_info[i].cached_items,
1446
0
           ctx->pool_info[i].need_avg, ctx->pool_info[i].failed_items,
1447
0
           ctx->pool_info[i].entry->users, ctx->pool_info[i].entry,
1448
0
           (ctx->pool_info[i].entry->flags & MEM_F_SHARED) ? " [SHARED]" : "");
1449
1450
0
    if (ctx->how & 0x10) { // print details
1451
0
      struct pool_registration *reg;
1452
1453
0
      list_for_each_entry(reg, &ctx->pool_info[i].entry->regs, list) {
1454
0
        chunk_appendf(&trash, "      >  %-12s: size=%llu flags=%#x align=%u", reg->name, reg->size, reg->flags, reg->align);
1455
0
        if (reg->file && reg->line)
1456
0
          chunk_appendf(&trash, " [%s:%u]", reg->file, reg->line);
1457
0
        chunk_appendf(&trash, "\n");
1458
0
      }
1459
0
    }
1460
1461
0
    if (applet_putchk(appctx, &trash) == -1) {
1462
0
      ctx->pool_idx = i;
1463
0
      return 0;
1464
0
    }
1465
0
  }
1466
1467
0
  chunk_printf(&trash, "Total: %d pools, %llu bytes allocated, %llu used"
1468
0
         " (~%llu by thread caches)"
1469
0
         ".\n",
1470
0
         ctx->nbpools, ctx->allocated, ctx->used, ctx->cached_bytes
1471
0
    );
1472
0
  if (applet_putchk(appctx, &trash) == -1)
1473
0
    return 0;
1474
1475
0
  return 1;
1476
0
}
1477
1478
/* This function returns the total number of failed pool allocations */
1479
int pool_total_failures()
1480
0
{
1481
0
  struct pool_head *entry;
1482
0
  int failed = 0;
1483
1484
0
  list_for_each_entry(entry, &pools, list)
1485
0
    failed += pool_failed(entry);
1486
0
  return failed;
1487
0
}
1488
1489
/* This function returns the total amount of memory allocated in pools (in bytes) */
1490
unsigned long long pool_total_allocated()
1491
0
{
1492
0
  struct pool_head *entry;
1493
0
  unsigned long long allocated = 0;
1494
1495
0
  list_for_each_entry(entry, &pools, list)
1496
0
    allocated += pool_allocated(entry) * (ullong)entry->size;
1497
0
  return allocated;
1498
0
}
1499
1500
/* This function returns the total amount of memory used in pools (in bytes) */
1501
unsigned long long pool_total_used()
1502
0
{
1503
0
  struct pool_head *entry;
1504
0
  unsigned long long used = 0;
1505
1506
0
  list_for_each_entry(entry, &pools, list)
1507
0
    used += pool_used(entry) * (ullong)entry->size;
1508
0
  return used;
1509
0
}
1510
1511
/* This function parses a string made of a set of debugging features as
1512
 * specified after -dM on the command line, and will set pool_debugging
1513
 * accordingly. On success it returns a strictly positive value. It may zero
1514
 * with the first warning in <err>, -1 with a help message in <err>, or -2 with
1515
 * the first error in <err> return the first error in <err>. <err> is undefined
1516
 * on success, and will be non-null and locally allocated on help/error/warning.
1517
 * The caller must free it. Warnings are used to report features that were not
1518
 * enabled at build time, and errors are used to report unknown features.
1519
 */
1520
int pool_parse_debugging(const char *str, char **err)
1521
0
{
1522
0
  struct ist args;
1523
0
  char *end;
1524
0
  uint new_dbg;
1525
0
  int v;
1526
1527
1528
  /* if it's empty or starts with a number, it's the mem poisonning byte */
1529
0
  v = strtol(str, &end, 0);
1530
0
  if (!*end || *end == ',') {
1531
0
    mem_poison_byte = *str ? v : 'P';
1532
0
    if (mem_poison_byte >= 0)
1533
0
      pool_debugging |=  POOL_DBG_POISON;
1534
0
    else
1535
0
      pool_debugging &= ~POOL_DBG_POISON;
1536
0
    str = end;
1537
0
  }
1538
1539
0
  new_dbg = pool_debugging;
1540
1541
0
  for (args = ist(str); istlen(args); args = istadv(istfind(args, ','), 1)) {
1542
0
    struct ist feat = iststop(args, ',');
1543
1544
0
    if (!istlen(feat))
1545
0
      continue;
1546
1547
0
    if (isteq(feat, ist("help"))) {
1548
0
      ha_free(err);
1549
0
      memprintf(err,
1550
0
          "-dM alone enables memory poisonning with byte 0x50 on allocation. A numeric\n"
1551
0
          "value may be appended immediately after -dM to use another value (0 supported).\n"
1552
0
          "Then an optional list of comma-delimited keywords may be appended to set or\n"
1553
0
          "clear some debugging options ('*' marks the current setting):\n\n"
1554
0
          "    set               clear            description\n"
1555
0
          "  -----------------+-----------------+-----------------------------------------\n");
1556
1557
0
      for (v = 0; dbg_options[v].flg; v++) {
1558
0
        memprintf(err, "%s  %c %-15s|%c %-15s| %s\n",
1559
0
            *err,
1560
0
            (pool_debugging & dbg_options[v].flg) ? '*' : ' ',
1561
0
            dbg_options[v].set,
1562
0
            (pool_debugging & dbg_options[v].flg) ? ' ' : '*',
1563
0
            dbg_options[v].clr,
1564
0
            dbg_options[v].hlp);
1565
0
      }
1566
1567
0
      memprintf(err,
1568
0
                "%s  -----------------+-----------------+-----------------------------------------\n"
1569
0
          "Examples:\n"
1570
0
          "  Disable merging and enable poisonning with byte 'P': -dM0x50,no-merge\n"
1571
0
          "  Randomly fail allocations: -dMfail\n"
1572
0
          "  Detect out-of-bound corruptions: -dMno-merge,tag\n"
1573
0
          "  Detect post-free cache corruptions: -dMno-merge,cold-first,integrity,caller\n"
1574
0
          "  Detect all cache corruptions: -dMno-merge,cold-first,integrity,tag,caller\n"
1575
0
          "  Detect UAF (disables cache, very slow): -dMuaf\n"
1576
0
          "  Detect post-cache UAF: -dMuaf,cache,no-merge,cold-first,integrity,tag,caller\n"
1577
0
          "  Detect post-free cache corruptions: -dMno-merge,cold-first,integrity,caller\n",
1578
0
                *err);
1579
0
      return -1;
1580
0
    }
1581
1582
0
    for (v = 0; dbg_options[v].flg; v++) {
1583
0
      if (isteq(feat, ist(dbg_options[v].set))) {
1584
0
        new_dbg |= dbg_options[v].flg;
1585
        /* UAF implicitly disables caching, but it's
1586
         * still possible to forcefully re-enable it.
1587
         */
1588
0
        if (dbg_options[v].flg == POOL_DBG_UAF)
1589
0
          new_dbg |= POOL_DBG_NO_CACHE;
1590
        /* fail should preset the tune.fail-alloc ratio to 1%  */
1591
0
        if (dbg_options[v].flg == POOL_DBG_FAIL_ALLOC)
1592
0
          mem_fail_rate = 1;
1593
0
        break;
1594
0
      }
1595
0
      else if (isteq(feat, ist(dbg_options[v].clr))) {
1596
0
        new_dbg &= ~dbg_options[v].flg;
1597
        /* no-fail should reset the tune.fail-alloc ratio */
1598
0
        if (dbg_options[v].flg == POOL_DBG_FAIL_ALLOC)
1599
0
          mem_fail_rate = 0;
1600
0
        break;
1601
0
      }
1602
0
    }
1603
1604
0
    if (!dbg_options[v].flg) {
1605
0
      memprintf(err, "unknown pool debugging feature <%.*s>", (int)istlen(feat), istptr(feat));
1606
0
      return -2;
1607
0
    }
1608
0
  }
1609
1610
0
  pool_debugging = new_dbg;
1611
0
  return 1;
1612
0
}
1613
1614
/* parse a "show pools" command. It returns 1 on failure, 0 if it starts to dump. */
1615
static int cli_parse_show_pools(char **args, char *payload, struct appctx *appctx, void *private)
1616
0
{
1617
0
  struct show_pools_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
1618
0
  int arg;
1619
1620
0
  for (arg = 2; *args[arg]; arg++) {
1621
0
    if (strcmp(args[arg], "byname") == 0) {
1622
0
      ctx->how = (ctx->how & ~0xF) | 1; // sort output by name
1623
0
    }
1624
0
    else if (strcmp(args[arg], "bysize") == 0) {
1625
0
      ctx->how = (ctx->how & ~0xF) | 2; // sort output by item size
1626
0
    }
1627
0
    else if (strcmp(args[arg], "byusage") == 0) {
1628
0
      ctx->how = (ctx->how & ~0xF) | 3; // sort output by total allocated size
1629
0
    }
1630
0
    else if (strcmp(args[arg], "detailed") == 0) {
1631
0
      ctx->how |= 0x10;                 // print detailed registrations
1632
0
    }
1633
0
    else if (strcmp(args[arg], "match") == 0 && *args[arg+1]) {
1634
0
      ctx->prefix = strdup(args[arg+1]); // only pools starting with this
1635
0
      if (!ctx->prefix)
1636
0
        return cli_err(appctx, "Out of memory.\n");
1637
0
      arg++;
1638
0
    }
1639
0
    else if (isdigit((unsigned char)*args[arg])) {
1640
0
      ctx->maxcnt = atoi(args[arg]); // number of entries to dump
1641
0
    }
1642
0
    else
1643
0
      return cli_err(appctx, "Expects either 'byname', 'bysize', 'byusage', 'match <pfx>', 'detailed', or a max number of output lines.\n");
1644
0
  }
1645
1646
0
  if (get_show_pools_info(ctx) == -1)
1647
0
    return cli_err(appctx, "Failed to get info about pools.\n");
1648
0
  return 0;
1649
0
}
1650
1651
/* release the "show pools" context */
1652
static void cli_release_show_pools(struct appctx *appctx)
1653
0
{
1654
0
  struct show_pools_ctx *ctx = appctx->svcctx;
1655
1656
0
  ha_free(&ctx->pool_info);
1657
0
  ha_free(&ctx->prefix);
1658
0
}
1659
1660
/* This function dumps memory usage information onto the stream connector's
1661
 * read buffer. It returns 0 as long as it does not complete, non-zero upon
1662
 * completion.
1663
 */
1664
static int cli_io_handler_dump_pools(struct appctx *appctx)
1665
0
{
1666
0
  return dump_pools_info(appctx);
1667
0
}
1668
1669
/* callback used to create early pool <name> of size <size> and store the
1670
 * resulting pointer into <ptr>. If the allocation fails, it quits with after
1671
 * emitting an error message.
1672
 */
1673
void create_pool_callback(struct pool_head **ptr, char *name, struct pool_registration *reg)
1674
0
{
1675
0
  *ptr = create_pool_from_reg(name, reg);
1676
0
  if (!*ptr) {
1677
0
    ha_alert("Failed to allocate pool '%s' of size %llu : %s. Aborting.\n",
1678
0
       name, reg->size, strerror(errno));
1679
0
    exit(1);
1680
0
  }
1681
0
}
1682
1683
/* Initializes all per-thread arrays on startup */
1684
static void init_pools()
1685
0
{
1686
0
  int thr;
1687
1688
0
  for (thr = 0; thr < MAX_THREADS; thr++) {
1689
0
    LIST_INIT(&ha_thread_ctx[thr].pool_lru_head);
1690
0
  }
1691
1692
0
  detect_allocator();
1693
0
}
1694
1695
INITCALL0(STG_PREPARE, init_pools);
1696
1697
/* Report in build options if trim is supported */
1698
static void pools_register_build_options(void)
1699
0
{
1700
0
  if (!using_default_allocator) {
1701
0
    char *ptr = NULL;
1702
0
    memprintf(&ptr, "Running with a replaced memory allocator (e.g. via LD_PRELOAD).");
1703
0
    hap_register_build_opts(ptr, 1);
1704
0
    mark_tainted(TAINTED_REPLACED_MEM_ALLOCATOR);
1705
0
  }
1706
0
}
1707
INITCALL0(STG_REGISTER, pools_register_build_options);
1708
1709
/* register cli keywords */
1710
static struct cli_kw_list cli_kws = {{ },{
1711
  { { "show", "pools",  NULL }, "show pools [by*] [match <pfx>] [nb]     : report information about the memory pools usage", cli_parse_show_pools, cli_io_handler_dump_pools, cli_release_show_pools },
1712
  {{},}
1713
}};
1714
1715
INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
1716
1717
1718
/* config parser for global "tune.fail-alloc" */
1719
static int mem_parse_global_fail_alloc(char **args, int section_type, struct proxy *curpx,
1720
                                       const struct proxy *defpx, const char *file, int line,
1721
                                       char **err)
1722
0
{
1723
0
  if (too_many_args(1, args, err, NULL))
1724
0
    return -1;
1725
0
  mem_fail_rate = atoi(args[1]);
1726
0
  if (mem_fail_rate < 0 || mem_fail_rate > 100) {
1727
0
      memprintf(err, "'%s' expects a numeric value between 0 and 100.", args[0]);
1728
0
      return -1;
1729
0
  }
1730
0
  return 0;
1731
0
}
1732
1733
/* config parser for global "tune.memory.hot-size" */
1734
static int mem_parse_global_hot_size(char **args, int section_type, struct proxy *curpx,
1735
                                       const struct proxy *defpx, const char *file, int line,
1736
                                       char **err)
1737
0
{
1738
0
  long size;
1739
1740
0
  if (too_many_args(1, args, err, NULL))
1741
0
    return -1;
1742
1743
0
  size = atol(args[1]);
1744
0
  if (size <= 0) {
1745
0
      memprintf(err, "'%s' expects a strictly positive value.", args[0]);
1746
0
      return -1;
1747
0
  }
1748
1749
0
  global.tune.pool_cache_size = size;
1750
0
  return 0;
1751
0
}
1752
1753
/* config parser for global "no-memory-trimming" */
1754
static int mem_parse_global_no_mem_trim(char **args, int section_type, struct proxy *curpx,
1755
                                       const struct proxy *defpx, const char *file, int line,
1756
                                       char **err)
1757
0
{
1758
0
  if (too_many_args(0, args, err, NULL))
1759
0
    return -1;
1760
0
  disable_trim = 1;
1761
0
  return 0;
1762
0
}
1763
1764
/* register global config keywords */
1765
static struct cfg_kw_list mem_cfg_kws = {ILH, {
1766
  { CFG_GLOBAL, "tune.fail-alloc", mem_parse_global_fail_alloc },
1767
  { CFG_GLOBAL, "tune.memory.hot-size", mem_parse_global_hot_size },
1768
  { CFG_GLOBAL, "no-memory-trimming", mem_parse_global_no_mem_trim },
1769
  { 0, NULL, NULL }
1770
}};
1771
1772
INITCALL1(STG_REGISTER, cfg_register_keywords, &mem_cfg_kws);
1773
1774
/*
1775
 * Local variables:
1776
 *  c-indent-level: 8
1777
 *  c-basic-offset: 8
1778
 * End:
1779
 */