Changeset 76

Show
Ignore:
Timestamp:
05/31/05 00:59:47 (4 years ago)
Author:
jtv
Message:

Unified logging; revamped free-space estimation algorithm

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • TODO

    r72 r76  
    1 Policy 
    2  - Stabilize behaviour of that very first swapfile (allocate small "zero" file?) 
     1Error Reporting 
     2 - Unify logging/printing code: print-only or dynamic choice 
     3 - Ensure minimal repetition of error/warning messages 
    34 
    4 Prettiness 
    5  - Unify logging/printing code: print-only or dynamic choice 
    65 
     6Policy Weaknesses 
     7 
     8Current policy is a bit weak when it comes to filesystem caching.  The problem 
     9is that cache populations grow and grow until they hit the limit of available 
     10physical memory--creating an arguably false impression of memory shortage.  The 
     11flexibility of the Linux virtual memory subsystem makes this, as far as I can 
     12see at this stage, impossible to diagnose directly. 
     13 
     14Most noticeable symptom: existing swapfiles are freed up sometime between system 
     15boot (when little data is cached and most physical memory is still free) and the 
     16moment when ever-growing caches push the percentage of free memory below our 
     17daemon's allocation threshold.  We end up allocating a new swapfile shortly 
     18after deallocating our last one, just as the user is getting into the swing of 
     19things and expects his system to respond smoothly.  While we're setting up that 
     20new swapfile, it doesn't.  This is hard to anticipate; starting up in bull mode 
     21may help as a practical matter by deferring the decision to deallocate, but 
     22only if the associated cooldown period is long enough for filesystem caches to 
     23fill up again and bring the system into a "steady state." 
     24 
     25There are other cases that can trigger this behaviour, though.  Consider this 
     26situation: some application X eats up huge amounts of virtual memory, most of 
     27which is in active use and therefore resides in physical memory.  Swap is full 
     28of rarely-used virtual memory pages.  Little or no filesystem caching occurs. 
     29Next, X finishes and suddenly we have lots of free physical memory--although 
     30swap remains densely populated.  I'll need to do some math (probably quite 
     31simple, once I have the right formula) to figure out what can and cannot happen 
     32here. 
     33 
     34Scenario A: if most of the swapped-out data is touched again before we go into 
     35bear mode and consider deallocating, we're fine.  We'll end up freeing largely 
     36unused swap space. 
     37 
     38Scenario B: if swap is deallocated at this stage, any remaining data it held 
     39will have to be read back in a hurry--plus, continued system operation may be 
     40suboptimal because some of that data is "colder" than filesystem data that could 
     41have been cached in the physical memory that X left free in its wake. 
     42 
     43Scenario C: if the "data vacuum" left by X is filled up by filesystem caches, we 
     44may end up thinking (once again) that we're short on memory--and allocating swap 
     45space that we won't be needing at all.  Bull mode will be prolonged when a 
     46return to bear mode is in order. 
     47 
     48One consolation: since filesystem caches are never swapped to disk, they cannot 
     49exceed physical memory size.  This means that the algorithm, for any acceptable 
     50set of parameters, can "overshoot" by at most a single swapfile. 
     51 
     52We could try to distinguish "false shortages" from real memory needs by 
     53ensuring that there is some "tripwire swap"--perhaps an existing conventional 
     54swap partition, or a special swapfile numbered zero.  An increase in the 
     55population of this swap would indicate true memory shortage.  The only problem 
     56is that the system may not resort to using the tripwire swap until it is already 
     57desperate!  Can we set a positive priority to make the tripwire slightly more 
     58sensitive?  We'd also have to clean this file up from time to time, because once 
     59it fills up the mechanism breaks down. 
     60 
     61 
     62Bull/Bear Mode 
     63 
     64Currently, the program goes into bear mode if swapfile allocation fails and into 
     65bull mode when swapfiles are allocated.  In the steady state we're somewhere 
     66inbetween.  Maybe this isn't the best way to do it. 
     67 
     68What if we inhibited deallocations not just in bull mode, but instead required 
     69that the percentage of available space was above the deallocation limit for an 
     70entire cooldown period? 
     71 
  • debian/changelog

    r75 r76  
     1swapspace (1.3) unstable; urgency=low 
     2 
     3  * Consider part of non-dirty cached memory to be free space 
     4  * Unified logging code--it's not pretty, but it's prettier 
     5  * No longer bother with "negotiable" minimum swapfile sizes 
     6  * Clarified startup message ("require n extra bytes" to "would prefer []") 
     7  * Documented existing policy weaknesses, possible solutions 
     8  * Systematic rounding of swap sizes to page size 
     9 
     10 -- Jeroen T. Vermeulen <jtv@sipa.or.th>  Thu, 26 May 2005 17:00:00 +0700 
     11 
    112swapspace (1.2) unstable; urgency=low 
    213 
    314  * Initial Debian package. 
    415 
    5  -- Jeroen T. Vermeulen <jtv@sipa.or.th>  Fry, 20 May 2005 14:00:00 +0700 
     16 -- Jeroen T. Vermeulen <jtv@sipa.or.th>  Fri, 20 May 2005 14:00:00 +0700 
    617 
  • src/Makefile

    r59 r76  
    1616hog : hog.o 
    1717 
    18 log.o : log.c log.h main.h 
     18log.o : log.c log.h main.h memory.h 
    1919 
    20 main.o : main.c config.h env.h main.h memory.h support.h 
     20main.o : main.c config.h env.h log.h main.h memory.h support.h 
    2121 
    22 memory.o : memory.c config.h env.h main.h memory.h support.h 
     22memory.o : memory.c config.h env.h log.h main.h memory.h support.h 
    2323 
    2424opts.o : opts.c opts.h main.h 
     
    2626support.o : support.c config.h env.h support.h 
    2727 
    28 swaps.o : swaps.c config.h env.h support.h swaps.h 
     28swaps.o : swaps.c config.h env.h log.h main.h memory.h support.h swaps.h 
    2929 
    3030clean : 
  • src/log.c

    r59 r76  
    1616Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
    1717*/ 
     18#include <errno.h> 
     19#include <stdio.h> 
     20#include <string.h> 
     21 
    1822#include "log.h" 
    1923 
    2024static bool logging = false; 
    21  
    2225 
    2326#ifndef LOG_PERROR 
     
    3740 
    3841 
    39 bool am_logging(void) 
    40 { 
    41   return logging; 
    42 } 
    43  
    44  
    4542/// Stop logging, e.g. because storage containing log name goes out of scope 
    4643void log_close() 
     
    5047} 
    5148 
     49 
     50static const char *prefix(int priority) 
     51{ 
     52  switch (priority) 
     53  { 
     54  case LOG_ERR:         return "Error: "; 
     55  case LOG_WARNING:     return "Warning: "; 
     56  case LOG_NOTICE:      return "Notice: "; 
     57  } 
     58  return ""; 
     59} 
     60 
     61 
     62static FILE *stream(int priority) 
     63{ 
     64  switch (priority) 
     65  { 
     66  case LOG_ERR: 
     67  case LOG_WARNING: 
     68    return stderr; 
     69  } 
     70  return stdout; 
     71} 
     72 
     73 
     74void log_msg(int priority, const char msg[]) 
     75{ 
     76  if (logging) syslog(priority, "%s", msg); 
     77  else         fprintf(stream(priority), "%s%s\n", prefix(priority), msg); 
     78} 
     79 
     80 
     81void log_perr(int priority, const char msg[]) 
     82{ 
     83  log_perrno(priority, msg, errno); 
     84} 
     85 
     86 
     87void log_perrno(int priority, const char msg[], int fault_errno) 
     88{ 
     89  if (!fault_errno) 
     90    log_msg(priority, msg); 
     91  else 
     92  { 
     93    const char *std = strerror(fault_errno); 
     94    if (logging) syslog(priority, "%s: %s", msg, std); 
     95    else fprintf(stream(priority), "%s%s: %s\n", prefix(priority), msg, std); 
     96  } 
     97} 
     98 
     99 
     100void log_str(int priority, const char msg[], const char arg[]) 
     101{ 
     102  if (logging) syslog(priority, "%s '%s'", msg, arg); 
     103  else fprintf(stream(priority), "%s%s '%s'\n", prefix(priority), msg, arg); 
     104} 
     105 
     106 
     107void log_perr_str(int priority, const char msg[], const char arg[]) 
     108{ 
     109  const int fault_errno = errno; 
     110  if (!fault_errno) 
     111  { 
     112    log_str(priority, msg, arg); 
     113  } 
     114  else 
     115  { 
     116    const char *std = strerror(fault_errno); 
     117    if (logging) 
     118      syslog(priority, "%s '%s': %s", msg, arg, std); 
     119    else 
     120      fprintf(stream(priority),"%s%s '%s': %s\n",prefix(priority),msg,arg,std); 
     121  } 
     122} 
     123 
     124 
     125void log_int(int priority, const char msg[], int arg) 
     126{ 
     127  if (logging) syslog(priority, "%s, %d", msg, arg); 
     128  else fprintf(stream(priority), "%s%s %d\n", prefix(priority), msg, arg); 
     129} 
     130 
     131 
     132void log_discrep(int priority, 
     133    const char msg[], 
     134    int swapfile, 
     135    memsize_t expected, 
     136    memsize_t found) 
     137{ 
     138  if (logging) 
     139    syslog(priority, 
     140        "Discrepancy in swapfile %d: %s (%lld bytes vs. %lld)", 
     141        swapfile, 
     142        msg, 
     143        expected, 
     144        found); 
     145  else 
     146    fprintf(stream(priority), 
     147        "%sDiscrepancy in swapfile %d: %s (%lld bytes vs. %lld)\n", 
     148        prefix(priority), 
     149        swapfile, 
     150        msg, 
     151        expected, 
     152        found); 
     153} 
     154 
  • src/log.h

    r59 r76  
    2222 
    2323#include "main.h" 
     24#include "memory.h" 
    2425 
    2526/// Open log, with given program name (string storage must remain available!) 
    2627void log_start(const char myname[]); 
    2728 
    28 /// Has logging been enabled?  If not, try writing any messages to stderr 
    29 bool am_logging(void); 
    30  
    3129/// Stop logging, e.g. because storage containing log name goes out of scope 
    3230void log_close(); 
    3331 
     32/// Write plain message to log, or standard output/error as appropriate 
     33void log_msg(int priority, const char msg[]); 
     34 
     35/// Log plain message followed by quoted string 
     36void log_str(int priority, const char msg[], const char arg[]); 
     37 
     38/// Log message in perror() style (i.e. with errno-based message appended) 
     39void log_perr(int priority, const char msg[]); 
     40 
     41/// Log message with given errno (or ignore error number if it is zero) 
     42void log_perrno(int priority, const char msg[], int fault_errno); 
     43 
     44/// Log message, perror()-style, but appending a quoted string 
     45void log_perr_str(int priority, const char msg[], const char arg[]); 
     46 
     47/// Log message, but appending an integer argument 
     48void log_int(int priority, const char msg[], int arg); 
     49 
     50/// Log logfile size discrepancy 
     51void log_discrep(int priority, 
     52    const char msg[], 
     53    int swapfile, 
     54    memsize_t expected, 
     55    memsize_t found); 
     56 
    3457#endif 
    3558 
  • src/main.c

    r59 r76  
    7878static volatile bool print_status=false; 
    7979 
     80/// Was an immediate adjustment requested? 
    8081static volatile bool adjust_swap=false; 
    8182 
     
    9495  if (unlikely(write(pidfd, localbuf, len) < len)) 
    9596  { 
    96     fprintf(stderr, "Could not write pidfile %s: %s\n",pidfile,strerror(errno)); 
     97    log_perr_str(LOG_ERR, "Could not write pidfile", pidfile); 
    9798    return false; 
    9899  } 
     
    114115  if (unlikely(pidfd == -1)) 
    115116  { 
    116     const int err = errno; 
    117     if (err == EEXIST) 
    118       fprintf(stderr, 
    119           "Daemon already running, or leftover pidfile %s\n", 
    120           pidfile); 
     117    if (errno == EEXIST) 
     118      log_str(LOG_ERR, "Daemon already running, or leftover pidfile", pidfile); 
    121119    else 
    122       fprintf(stderr, 
    123           "Could not create pidfile %s: %s\n", 
    124           pidfile, 
    125           strerror(errno)); 
     120      log_perr_str(LOG_ERR, "Could not create pidfile", pidfile); 
    126121    return false; 
    127122  } 
     
    207202static void handle_requirements(void) 
    208203{ 
    209     const memsize_t req = memory_target(); 
    210     // TODO: Is minimum required swapfile size still relevant? 
    211     if (req > 0)        alloc_swapfile(req, req/4); 
    212     else if (req < 0)   free_swapfile(-req); 
     204  const memsize_t req = memory_target(); 
     205  if (req > 0)          alloc_swapfile(req); 
     206  else if (req < 0)     free_swapfile(-req); 
    213207} 
    214208 
  • src/memory.c

    r59 r76  
    3939static int freetarget=25; 
    4040 
     41// TODO: Make this adaptive based on actual cache usage, to avoid thrashing? 
     42/// Configuration item: what percentage of cache space do we consider "free"? 
     43static int cache_meekness=50; 
     44 
    4145char *set_freetarget(long long pct) 
    4246{ 
     
    5660  return NULL; 
    5761} 
     62 
     63char *set_cache_meekness(long long pct) 
     64{ 
     65  cache_meekness = (int)pct; 
     66  return NULL; 
     67} 
     68 
    5869 
    5970bool memory_check_config(void) 
     
    147158  memsize_t MemTotal, 
    148159            MemFree, 
     160            Cached, 
     161            Dirty, 
     162            Writeback, 
     163            SwapCached, 
    149164            SwapTotal, 
    150165            SwapFree; 
     
    156171  switch (inf->entry[0]) 
    157172  { 
     173  case 'C': 
     174    if (strcmp(inf->entry, "Cached:")==0)          st->Cached = inf->value; 
     175    break; 
     176  case 'D': 
     177    if (strcmp(inf->entry, "Dirty:")==0)           st->Dirty = inf->value; 
     178    break; 
    158179  case 'M': 
    159     if (strcmp(inf->entry, "MemTotal:") == 0) st->MemTotal = inf->value; 
    160     else if (strcmp(inf->entry, "MemFree:") == 0) st->MemFree = inf->value; 
     180    if (strncmp(inf->entry,"Mem",3) == 0) 
     181    { 
     182      if (strcmp(inf->entry+3, "Total:")==0)       st->MemTotal = inf->value; 
     183      else if (strcmp(inf->entry+3, "Free:")==0)   st->MemFree = inf->value; 
     184    } 
    161185    break; 
    162186  case 'S': 
    163     if (strcmp(inf->entry, "SwapTotal:") == 0) st->SwapTotal = inf->value; 
    164     else if (strcmp(inf->entry, "SwapFree:") == 0) st->SwapFree = inf->value; 
     187    if (strncmp(inf->entry,"Swap",4) == 0) 
     188    { 
     189      if (strcmp(inf->entry+4, "Total:")==0)       st->SwapTotal = inf->value; 
     190      else if (strcmp(inf->entry+4, "Free:")==0)   st->SwapFree = inf->value; 
     191      else if (strcmp(inf->entry+4, "Cached:")==0) st->SwapCached = inf->value; 
     192    } 
     193    break; 
     194  case 'W': 
     195    if (strcmp(inf->entry,"Writeback:")==0)        st->Writeback = inf->value; 
    165196    break; 
    166197  } 
     
    173204  if (unlikely(!fp)) 
    174205  { 
    175     if (am_logging()) 
    176         syslog(LOG_ERR, "Could not open /proc/meminfo for reading: %m"); 
    177     else 
    178         perror("Could not open /proc/meminfo for reading"); 
     206    log_perr(LOG_ERR, "Could not open /proc/meminfo for reading"); 
    179207    return false; 
    180208  } 
     
    183211  while (read_meminfo_item(fp, &inf)) imbibe_meminfo_entry(&inf, result); 
    184212  fclose(fp); 
    185   if (unlikely(inf.entry[0])) 
    186   { 
    187     if (am_logging()) 
    188     { 
    189       if (inf.value) syslog(LOG_ERR, "%s: %m", inf.entry); 
    190       else syslog(LOG_ERR, "%s", inf.entry); 
    191     } 
    192     else 
    193     { 
    194       if (inf.value) fprintf(stderr,"%s: %s\n",inf.entry,strerror(inf.value)); 
    195       else fputs(inf.entry, stderr); 
    196     } 
    197   } 
     213  if (unlikely(inf.entry[0])) log_perrno(LOG_ERR, inf.entry, inf.value); 
    198214   
    199215  return true; 
     
    207223  { 
    208224    printf("Initial memory status: "); 
    209     if (init_req > 0) printf("require %lld extra bytes\n", init_req); 
     225    if (init_req > 0) printf("would prefer %lld extra bytes\n", init_req); 
    210226    else if (init_req < 0) printf("%lld bytes to spare\n", -init_req); 
    211227  } 
     
    214230 
    215231 
     232/// How much cache space can we expect the system to free up? 
     233static inline memsize_t cache_free(const struct memstate *st) 
     234{ 
     235  const memsize_t cache = st->Cached - (st->Dirty + st->Writeback); 
     236  return (cache > 0) ? (cache/100)*cache_meekness : 0; 
     237} 
     238 
     239 
    216240static inline memsize_t space_free(const struct memstate *st) 
    217241{ 
    218   return st->MemFree + st->SwapFree; 
     242  /* Estimating "free" memory is not only hard, but subjective as well.  Ideally 
     243   * we'd want some measure of "pressure"--which we don't seem to have. 
     244   * 
     245   * The big question is what to do about Cached.  This is where most bytes tend 
     246   * to go, and it grows unless and until memory requirements get really, really 
     247   * urgent.  In other words, it doesn't behave as if it's something very 
     248   * flexible that we could treat as essentially "free" space. 
     249   * 
     250   * What if we subtracted Dirty and Writeback from this number?  Writeback 
     251   * appears to be a very rare state, but Dirty can get quite large when the 
     252   * system is pressed for memory.  Would the remainder be more or less 
     253   * flexible?  For some reason I get more flexibility now, even without having 
     254   * a noticeable number of dirty pages, on a 2.6.10 kernel than I observed in 
     255   * the past.  Has something changed here? 
     256   * 
     257   * I managed to push back Cached all the way to about half a percent of total 
     258   * physical memory before the system started to thrash.  And that was with a 
     259   * large number of applications loaded and large amounts of memory allocated 
     260   * and committed by applications. 
     261   * 
     262   * Under these circumstances, best thing to do is subtract Dirty/Writeback 
     263   * from Cached and "discount" the remainder against a new parameter ("Cache 
     264   * Pressure") which says how much of the non-dirty part of Cache should be 
     265   * considered in-use. 
     266   */ 
     267  return st->MemFree + st->SwapFree + st->SwapCached + cache_free(st); 
    219268} 
    220269 
     
    241290  assert(upper_freelimit > lower_freelimit); 
    242291 
    243   struct memstate st = { 0, 0, 0, 0 }; 
     292  struct memstate st = { 0, 0, 0, 0, 0, 0, 0, 0 }; 
    244293  if (unlikely(!read_proc_meminfo(&st))) return MEMSIZE_ERROR; 
    245294 
     
    248297 
    249298  // Policy: once we hit either freelimit, steer for "freetarget"% free space 
    250   // TODO: Use /proc/sys/vm/min_free_kbytes when no swap yet allocated 
     299  // TODO: Use /proc/sys/vm/min_free_kbytes when no swap yet allocated? 
    251300  if (freepct < lower_freelimit || freepct > upper_freelimit) 
    252301  { 
  • src/memory.h

    r59 r76  
    4040char *set_upper_freelimit(long long pct); 
    4141char *set_freetarget(long long pct); 
     42char *set_cache_meekness(long long pct); 
    4243 
    4344bool memory_check_config(void); 
  • src/opts.c

    r59 r76  
    6161static const struct option options[] = 
    6262{ 
     63  { "cache_meekness",   'w', at_num,  0, 100, set_cache_meekness, 
     64  "Consider n% of cache memory to be free space" }, 
    6365  { "configfile",       'c', at_str,  1, PATH_MAX, set_configfile, 
    6466  "Use configuration file s" }, 
  • src/swaps.c

    r72 r76  
    6161 
    6262/// Smallest allowed swapfile size 
    63 static memsize_t min_swapsize = 12*PAGE_SIZE
     63static memsize_t min_swapsize = (12*PAGE_SIZE) & PAGE_MASK
    6464/// Largest allowed swapfile size 
    6565/** Don't set this too low.  The program will learn if it runs into file size 
    6666 * limits. 
    6767 */ 
    68 static memsize_t max_swapsize = TERA
     68static memsize_t max_swapsize = TERA & PAGE_MASK
    6969 
    7070 
     
    100100char *set_min_swapsize(long long size) 
    101101{ 
    102   min_swapsize = (memsize_t)size
     102  min_swapsize = ((memsize_t)size & PAGE_MASK)
    103103  return NULL; 
    104104} 
     
    106106char *set_max_swapsize(long long size) 
    107107{ 
    108   max_swapsize = (memsize_t)size
     108  max_swapsize = ((memsize_t)size) & PAGE_MASK
    109109  return NULL; 
    110110} 
     
    119119bool swaps_check_config(void) 
    120120{ 
    121   assert(!am_logging()); 
    122121  CHECK_CONFIG_ERR(min_swapsize > max_swapsize); 
    123122 
    124123  if (chdir(swappath) == -1) 
    125124  { 
    126     fprintf(stderr, "Could not cd to %s: %s\n", swappath, strerror(errno)); 
     125    log_perr_str(LOG_ERR, "Coult not cd to", swappath); 
    127126    return false; 
    128127  } 
    129128  if (!getcwd(swappath, sizeof(swappath))) 
    130129  { 
    131     fputs("Swap path too long\n", stderr); 
     130    log_msg(LOG_ERR, "Swap path too long"); 
    132131    return false; 
    133132  } 
     
    141140  for (int i=swappath_len-1; i >= 0; --i) if (isspace(swappath[i])) 
    142141  { 
    143     fputs("Not supported: swap path contains whitespace\n", stderr); 
     142    log_msg(LOG_ERR, "Not supported: swap path contains whitespace"); 
    144143    return false; 
    145144  } 
     
    235234  runcommand("mkswap", file); 
    236235  const bool ok = (swapon(file, 0) == 0); 
    237   if (unlikely(!ok)) 
    238   { 
    239     if (am_logging())   syslog(LOG_ERR, "Unable to enable swapfile: %m"); 
    240     else                perror(file); 
    241   } 
     236  if (unlikely(!ok)) log_perr_str(LOG_ERR, "Could not enable swapfile", file); 
    242237  return ok; 
    243238} 
     
    270265  { 
    271266    const int err = errno; 
    272     if (am_logging())   syslog(LOG_ERR, "Error writing swap file: %m"); 
    273     else                perror("Error writing swap file"); 
     267    log_perrno(LOG_ERR, "Error writing swap file", err); 
    274268    bytes -= block; 
    275269    switch (err) 
     
    277271    case EFBIG: 
    278272      // File is too large.  Remember how much we were allowed to write. 
    279       if (likely(bytes > 0 && max_swapsize > bytes)) max_swapsize = bytes; 
     273      if (likely(bytes > 0 && max_swapsize > bytes)) 
     274        max_swapsize = (bytes & PAGE_MASK); 
    280275      break; 
    281276    case ENOSPC: 
     
    299294/** 
    300295 * @param filename File to be created 
    301  * @param size Desired size in bytes 
    302  * @param min Absolute required minimum size in bytes 
     296 * @param size Desired size in bytes (but already rounded to page size) 
    303297 * @return Size of new swapfile, which may differ from requested size.  Zero or 
    304298 * less indicates failure, in which case the file is deleted.  Negative result 
     
    306300 * likely to be appreciated. 
    307301 */ 
    308 static memsize_t make_swapfile(const char file[], memsize_t size, memsize_t min
     302static memsize_t make_swapfile(const char file[], memsize_t size
    309303{ 
    310304  assert(min_swapsize <= max_swapsize); 
     305  assert(!(max_swapsize & ~PAGE_MASK)); 
     306  assert(!(min_swapsize & ~PAGE_MASK)); 
     307  assert(!(size & ~PAGE_MASK)); 
     308 
     309  memsize_t realsize; 
     310 
     311  if (unlikely(size < min_swapsize)) return 0; 
    311312 
    312313  // Don't allocate swap for a while--we had a bad experience recently 
    313314  if (unlikely(cooldown_bear) && in_cooldown()) return 0; 
    314315 
    315   size = MIN(MAX(size-size%PAGE_SIZE, min_swapsize), max_swapsize); 
    316   min = MAX(min, min_swapsize); 
    317  
    318   if (unlikely(min > max_swapsize)) return false; // Ask too much, get nothing 
     316  size = MIN(size, max_swapsize); 
    319317 
    320318  // TODO: Think about reuse of existing swapfiles 
     
    323321  if (unlikely(fd == -1)) 
    324322  { 
    325     if (am_logging()) 
    326       syslog(LOG_ERR, "Could not create swapfile '%s': %m", file); 
    327     else 
    328       fprintf(stderr, 
    329           "Could not create swapfile '%s': %s\n", 
    330           file, 
    331           strerror(errno)); 
     323    log_perr_str(LOG_ERR, "Could not create swapfile", file); 
    332324    return 0; 
    333325  } 
    334   size = fill_swapfile(fd, size); 
     326  realsize = fill_swapfile(fd, size); 
    335327  close(fd); 
    336   if (unlikely(size < min)) 
     328  if (unlikely(realsize < size)) 
    337329  { 
    338330    unlink(file); 
     
    340332  } 
    341333   
    342   return size; 
     334  return realsize; 
    343335} 
    344336 
     
    371363  if (unlikely(fd == -1)) 
    372364  { 
    373     if (am_logging()) 
    374       syslog(LOG_WARNING, "Can't determine size of '%s': %m", name); 
    375     else 
    376       fprintf(stderr,"Can't determine size of '%s': %s\n",name,strerror(errno)); 
     365    log_perr_str(LOG_WARNING, "Can't determine size of", name); 
    377366    return -1; 
    378367  } 
     368 
    379369  memsize_t pos = SEEK(fd, 0, SEEK_END); 
    380370  if (unlikely(pos == -1)) 
    381   { 
    382     if (am_logging()) 
    383       syslog(LOG_WARNING, "Can't determine size of '%s': %m", name); 
    384     else 
    385       fprintf(stderr,"Can't determine size of '%s': %s\n",name,strerror(errno)); 
    386   } 
     371    log_perr_str(LOG_WARNING, "Can't determine size of", name); 
     372 
    387373  return pos; 
    388374} 
     
    391377bool activate_old_swaps(void) 
    392378{ 
    393   assert(!am_logging()); 
    394  
    395379  DIR *dir = opendir("."); 
    396380  if (unlikely(!dir)) 
    397381  { 
    398     perror("Cannot read swap directory"); 
     382    log_perr(LOG_ERR, "Cannot read swap directory"); 
    399383    return false; 
    400384  } 
     
    404388    if (valid_swapfile(d->d_name, &seqno) && !swapfiles[seqno].size) 
    405389    { 
    406       if (!quiet) printf("Found old swapfile %d\n", seqno); 
     390      if (!quiet) log_int(LOG_INFO, "Found old swapfile", seqno); 
    407391      const memsize_t size = filesize(d->d_name);  
    408       if (size > min_swapsize && enable_swapfile(d->d_name)) 
     392      if (likely(size > min_swapsize && enable_swapfile(d->d_name))) 
    409393      { 
    410394        swapfiles[seqno].size = size; 
     
    412396      else 
    413397      { 
    414         if (!quiet) printf("Can't swap to file %d.  Deleting it.\n", seqno); 
     398        if (!quiet) log_int(LOG_NOTICE, "Deleting unusable swap file", seqno); 
    415399        unlink(d->d_name); 
    416400      } 
     
    428412{ 
    429413  FILE *fp = fopen("/proc/swaps", "r"); 
    430   if (unlikely(!fp)) 
    431   { 
    432     if (am_logging())   syslog(LOG_ERR, "Could not open /proc/swaps: %m"); 
    433     else                perror("Could not open /proc/swaps"); 
    434   } 
     414  if (unlikely(!fp)) log_perr(LOG_ERR, "Could not open /proc/swaps"); 
    435415  return fp; 
    436416} 
     
    443423  if (unlikely(sscanf(localbuf, "Filename Type Size Used %c",&c) < 1)) 
    444424  { 
    445     fputs("/proc/swaps is not in the expected format\n", stderr); 
     425    log_msg(LOG_ERR, "/proc/swaps is not in the expected format"); 
    446426    return false; 
    447427  } 
     
    488468       * somewhere further down. 
    489469       */ 
    490       if (check_proc_swaps_header(localbuf)) continue; 
    491       if (am_logging()) 
    492         syslog(LOG_ERR, "Parse error in /proc/swaps: '%s'", localbuf); 
    493       else 
    494         fprintf(stderr, "Parse error in /proc/swaps: '%s'\n", localbuf); 
    495       return false; 
     470      if (!check_proc_swaps_header(localbuf)) 
     471      { 
     472        log_str(LOG_ERR, "Parse error in /proc/swaps:", localbuf); 
     473        return false; 
     474      } 
    496475    } 
    497476    // /proc/swaps appears to report sizes in 1 KB blocks 
     
    507486      { 
    508487        // We didn't know about this swapfile yet.  Adopt it. 
    509         if (!quiet) 
    510         { 
    511           if (am_logging()) 
    512             syslog(LOG_NOTICE, "Detected swapfile %d", result->seqno); 
    513           else 
    514             printf("Detected swapfile %d\n", result->seqno); 
    515         } 
     488        if (!quiet) log_int(LOG_NOTICE, "Detected swapfile", result->seqno); 
    516489        swapfiles[result->seqno].created = clock; 
    517490      } 
     
    522495        const memsize_t expected = swapfiles[result->seqno].size, 
    523496                        found = result->size; 
    524         const char *notice = NULL; 
    525         bool serious = false; 
     497 
    526498        if (unlikely(swapfiles[result->seqno].observed_in_wild)) 
    527         { 
    528           notice="Swapfile %d changed from %lld to %lld bytes!\n"; 
    529           serious = true; 
    530         } 
     499          log_discrep(LOG_NOTICE,"size changed",result->seqno,expected,found); 
    531500        else if (unlikely(found > expected)) 
    532         { 
    533           notice="Swapfile %d is larger than expected (%lld vs %lld bytes)!\n"; 
    534         } 
     501          log_discrep(LOG_INFO, 
     502              "larger than expected", 
     503              result->seqno, 
     504              expected, 
     505              found); 
    535506        else if (!quiet && unlikely(found < (expected + PAGE_SIZE))) 
    536         { 
    537           notice="Discrepancy in swapfile %d: expected %lld bytes, got %lld\n"; 
    538         } 
    539  
    540         if (unlikely(notice)) 
    541         { 
    542           if (am_logging()) 
    543             syslog((serious ? LOG_NOTICE : LOG_INFO), 
    544                 notice, 
    545                 result->seqno, 
    546                 expected, 
    547                 found); 
    548           else 
    549           { 
    550             if (serious) fprintf(stderr, "Warning: "); 
    551             fprintf((serious ? stderr : stdout), 
    552                 notice, 
    553                 result->seqno, 
    554                 expected, 
    555                 found); 
    556           } 
    557         } 
     507          log_discrep(LOG_INFO, 
     508              "smaller than expected", 
     509              result->seqno, 
     510              expected, 
     511              found); 
    558512      } 
    559513      if (!quiet && unlikely(result->used > result->size)) 
    560       { 
    561         if (am_logging()) 
    562           syslog(LOG_NOTICE, 
    563               "Discrepancy in swapfile %d: usage (%lld) > size (%lld)!", 
    564               result->seqno, 
    565               result->used, 
    566               result->size); 
    567         else 
    568           printf("Discrepancy in swapfile %d: usage (%lld) > size (%lld)!\n", 
    569               result->seqno, 
    570               result->used, 
    571               result->size); 
    572       } 
     514        log_discrep(LOG_NOTICE, 
     515            "usage exceeds size", 
     516            result->seqno, 
     517            result->used, 
     518            result->size); 
     519 
    573520      swapfiles[result->seqno].size = result->size; 
    574521      swapfiles[result->seqno].used = result->used; 
     
    617564   * they are still in use or things would get horribly confused. 
    618565   */ 
    619   if (!quiet) 
    620   { 
    621     if (am_logging())   syslog(LOG_INFO, "Retiring swapfile %d", file); 
    622     else                printf("Retiring swapfile %d\n",file); 
    623   } 
    624566  char namebuf[30]; 
    625567  snprintf(namebuf, sizeof(namebuf), "%d", file); 
     568  if (!quiet) log_str(LOG_NOTICE, "Retiring swapfile", namebuf); 
    626569  if (unlikely(swapoff(namebuf) == -1)) return false; 
    627570  swapfiles[file].size = 0; 
     
    668611 
    669612 
    670 // TODO: Do away with the "required" option.  Disk full means failure, period. 
    671 void alloc_swapfile(memsize_t requested, memsize_t required) 
     613void alloc_swapfile(memsize_t size) 
    672614{ 
    673615  /* Round request to page size, then add a bit for swapfile overhead.  Clever 
    674616   * readers will notice that this relies on PAGE_SIZE being a power of two. 
    675617   */ 
    676   requested = (requested & ~(PAGE_SIZE-1)) + 2*PAGE_SIZE; 
     618  size = (size & PAGE_MASK) + 2*PAGE_SIZE; 
    677619  const int newswap = find_free(sequence_number); 
    678620  if (swapfiles[newswap].size) return;  // No free slot, sorry! 
    679621 
    680622  // We can allocate another swapfile.  Great. 
     623  if (!quiet) log_int(LOG_NOTICE, "Allocating swapfile", newswap); 
    681624  char file[30]; 
    682625  snprintf(file, sizeof(file), "%d", newswap); 
    683   if (!quiet) 
    684   { 
    685     if (am_logging()) 
    686       syslog(LOG_NOTICE, "Allocating swapfile %s, size %llu (min %llu)\n", 
    687           file, 
    688           requested, 
    689           required); 
    690     else 
    691       printf("Allocating swapfile %s, size %llu (min %llu)\n", 
    692           file, 
    693           requested, 
    694           required); 
    695   } 
    696   swapfiles[newswap].size = make_swapfile(file, requested, required); 
     626  swapfiles[newswap].size = make_swapfile(file, size); 
    697627 
    698628  if (swapfiles[newswap].size) 
  • src/swaps.h

    r59 r76  
    5353/// Create a new swapfile.  Clobbers localbuf. 
    5454/** 
    55  * @param requested target size for new swapfile 
    56  * @param required minimum size for new swapfile 
     55 * @param size number of bytes to allocate 
    5756 */ 
    58 void alloc_swapfile(memsize_t requested, memsize_t required); 
     57void alloc_swapfile(memsize_t size); 
    5958 
    6059/// Free swap space