Changeset 81

Show
Ignore:
Timestamp:
06/16/05 21:29:30 (4 years ago)
Author:
jtv
Message:

Several improvements in error handling; don't deallocate swap if free memory
falls below threshold during cooldown period; ported to Linux 2.4

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • Makefile

    r73 r81  
    44SWAPDIR=$(SWAPPARENT)/swapspace 
    55 
    6 all: 
    7         +$(MAKE) -C src 
     6all: VERSION DATE 
     7        +$(MAKE) -C src VERSION="`cat VERSION`" DATE="`cat DATE`" 
    88 
    99clean: 
     
    2525        $(RM) /usr/share/man/man8/swapspace.8 
    2626 
     27# Derive version number and last change date from Debian changelog 
     28VERSION: debian/changelog 
     29        head -n 1 $< | sed -e 's/^.*(\([0-9][^)]*\)).*/\1/' >$@ 
     30 
     31DATE: debian/changelog 
     32        grep '^ -- ' $< | sed -e 's/^.*>  \([MTWFS][a-z]\{2\}, \{1,2\}[[:digit:]]\{1,2\} [JFBAMSOND][a-z]* 2[[:digit:]]\{3\}\) .*/\1/' | head -n 1 >$@ 
     33 
    2734.PHONY: all clean install uninstall 
    2835 
  • TODO

    r80 r81  
    22 - Print version number with help output; add --version option 
    33 - Ensure minimal repetition of error/warning messages 
    4  
    5  
    6 Bull/Bear Mode 
    7  
    8 Currently, the program goes into bear mode if swapfile allocation fails and into 
    9 bull mode when swapfiles are allocated.  In the steady state we're somewhere 
    10 inbetween.  Maybe this isn't the best way to do it. 
    11  
    12 What if we inhibited deallocations until the percentage of available space 
    13 remained above the deallocation limit for an entire cooldown period?  Currently 
    14 deallocation seems to be too aggressive. 
    15  
  • debian/changelog

    r77 r81  
     1swapspace (1.4) unstable; urgency=low 
     2 
     3  * Supports Linux 2.4's /proc/meminfo format; no longer requires 2.6 kernel 
     4  * Only deallocates if enough memory stays free for entire cooldown period 
     5  * Failure to parse /proc/meminfo is now fatal 
     6  * New --version option 
     7  * Additional sanity checking of memory statistics 
     8 
     9 -- Jeroen T. Vermeulen <jtv@sipa.or.th>  Thu, 16 June 2005 19:30:00 +0700 
     10 
    111swapspace (1.3) unstable; urgency=low 
    212 
  • src/Makefile

    r76 r81  
    11#! /usr/bin/make 
    22 
    3 #CC=gcc-3.4 
     3# Assumes we're using gcc 
    44CFLAGS=--std=c99 -Wall --pedantic -Wshadow -O2 -g 
    5 CPPFLAGS=-DSUPPORT_LARGE_FILES 
     5CPPFLAGS=-DSUPPORT_LARGE_FILES -DVERSION="\"$(VERSION)\"" -DDATE="\"$(DATE)\"" 
    66RM=rm -f 
    77 
     
    2222memory.o : memory.c config.h env.h log.h main.h memory.h support.h 
    2323 
    24 opts.o : opts.c opts.h main.h 
     24opts.o : opts.c opts.h main.h ../VERSION ../DATE 
    2525 
    2626support.o : support.c config.h env.h support.h 
  • src/main.c

    r76 r81  
    205205  if (req > 0)          alloc_swapfile(req); 
    206206  else if (req < 0)     free_swapfile(-req); 
     207  else                  steady_state(); 
    207208} 
    208209 
  • src/memory.c

    r78 r81  
    9797/** Attempt to read a line from /proc/meminfo into result.  If an error occurs, 
    9898 * result will hold errno (which may be zero, e.g. in the case of a parse error) 
    99  * and a generic error string.  If end-of-file has been reached, result will 
    100  * contain zero and the empty string. 
     99 * and a generic error string.  If end-of-file has been reached or a meaningless 
     100 * line has been read, result will contain zero and the empty string. 
    101101 * 
    102102 * @return success (not EOF and not error) 
     
    115115 
    116116  char fact[20]; 
    117   const int x = sscanf(localbuf,"%s %lld %s",result->entry,&result->value,fact); 
     117  const int x = sscanf(localbuf, 
     118      "%s %lld %19s", 
     119      result->entry, 
     120      &result->value, 
     121      fact); 
     122 
    118123  if (unlikely(x < 3)) 
    119124  { 
    120125    result->value = 0; 
     126 
     127    // In Linux 2.4, /proc/meminfo starts with a header line with leading 
     128    // whitespace.  We accept that as a special case. 
     129    if (likely(isspace(localbuf[0]))) 
     130    { 
     131      result->entry[0] = '\0'; 
     132      return true; 
     133    } 
     134 
     135    // All other parse failures are fatal. 
    121136    snprintf(result->entry, 
    122         sizeof(result->entry), 
    123         "Parse error in /proc/meminfo: '%150s'", 
    124         localbuf); 
    125     return false; 
    126   } 
    127  
     137          sizeof(result->entry), 
     138          "Parse error in /proc/meminfo: '%150s'", 
     139          localbuf); 
     140 
     141    return false; 
     142  } 
     143 
     144  // Another special case for Linux 2.4: two extra lines summarize the various 
     145  // pools of physical memory and swap space.  We'd fail to parse these lines 
     146  // (which we're not interested in anyway) because there's a number where we 
     147  // expect a scale factor.  Detect this and skip those lines. 
     148  if (isdigit(fact[0])) 
     149  { 
     150    result->entry[0] = '\0'; 
     151    result->value = 0; 
     152    return true; 
     153  } 
     154 
     155  // Parse scale factor at end of line.  I've never seen it be anything other 
     156  // than "kB", but who knows what can happen... 
    128157  memsize_t scale = 0; 
    129158  const size_t factlen = strlen(fact); 
     
    214243 
    215244 
    216 static bool read_proc_meminfo(struct memstate *result
     245static bool read_proc_meminfo(struct memstate *s
    217246{ 
    218247  FILE *fp = fopen("/proc/meminfo", "r"); 
     
    224253 
    225254  struct meminfo_item inf; 
    226   while (read_meminfo_item(fp, &inf)) imbibe_meminfo_entry(&inf, result); 
     255  while (read_meminfo_item(fp, &inf)) imbibe_meminfo_entry(&inf, s); 
    227256  fclose(fp); 
    228   if (unlikely(inf.entry[0])) log_perrno(LOG_ERR, inf.entry, inf.value); 
    229    
     257  if (unlikely(inf.entry[0])) 
     258  { 
     259    log_perrno(LOG_ERR, inf.entry, inf.value); 
     260    return false; 
     261  } 
     262  
     263  if (unlikely(!s->MemTotal)) 
     264  { 
     265    log_msg(LOG_ERR, 
     266        "No memory detected! Perhaps /proc/meminfo is in an unexpected format"); 
     267    return false; 
     268  } 
     269  if (unlikely(s->MemTotal < s->MemFree+s->Buffers+s->Cached+s->SwapCached)) 
     270  { 
     271    log_msg(LOG_ERR, "Memory statistics read from /proc/meminfo don't add up"); 
     272    return false; 
     273  } 
     274 
    230275  return true; 
    231276} 
     
    235280{ 
    236281  const memsize_t init_req = memory_target(); 
     282  if (init_req == MEMSIZE_ERROR) return false; 
    237283  if (init_req && !quiet) 
    238284  { 
     
    241287    else if (init_req < 0) printf("%lld bytes to spare\n", -init_req); 
    242288  } 
    243   return init_req != MEMSIZE_ERROR
     289  return true
    244290} 
    245291 
  • src/opts.c

    r77 r81  
    4141 
    4242static char *set_help(long long dummy); 
     43static char *set_version(long long dummy); 
    4344 
    4445 
     
    8889  "Create swapfiles in secure directory s" }, 
    8990  { "upper_freelimit",  'u', at_num,  0, 100, set_upper_freelimit, 
    90   "Reduce swapspace if more than n% is free" } 
     91  "Reduce swapspace if more than n% is free" }, 
     92  { "version",          'V', at_none, 0, 0, set_version, 
     93  "Print version number and exit" } 
    9194}; 
    9295 
     
    149152  return result; 
    150153} 
     154 
     155const char copyright[] = "\n" 
     156      "Copyright (c) 2004-2005 Software Industry Promotion Agency of Thailand\n" 
     157      "Written by Jeroen T. Vermeulen <jtv@sipa.or.th>\n" 
     158      "This program is free software, and is available for use under the GNU\n" 
     159      "General Public License (GPL).\n"; 
    151160 
    152161static char *set_help(long long dummy) 
     
    183192  } 
    184193 
    185   puts("\n\n" 
    186       "Copyright (c) 2004-2005 Software Industry Promotion Agency of Thailand\n" 
    187       "Written by Jeroen T. Vermeulen <jtv@sipa.or.th>\n" 
    188       "This program is free software, and is available for use under the GNU\n" 
    189       "General Public License (GPL).\n" 
    190       ); 
     194  puts(copyright); 
     195  exit(EXIT_SUCCESS); 
     196
     197 
     198 
     199char *set_version(long long dummy) 
     200
     201  puts("swapspace " VERSION ", " DATE); 
     202  puts(copyright); 
    191203  exit(EXIT_SUCCESS); 
    192204} 
  • src/swaps.c

    r79 r81  
    7272/// Minimum cooldown time between Bull/Bear policy reversals 
    7373/** The program's disposition to allocate or deallocate wavers between two 
    74  * extremes: Bull and Bear, though normal operation will take place in the 
    75  * grey area between them.  This is done to avoid unstable behaviour where swap 
     74 * extremes: Bull and Bear.  This is done to avoid unstable behaviour where swap 
    7675 * files are repeatedly created, deleted again, and then re-allocated. 
    7776 * 
     
    8079 * left unused.  While this phase lasts, the program will assume that any drop 
    8180 * in swap space usage may be temporary and the allocated swap files may be 
    82  * needed again soon. 
     81 * needed again soon.  Bull phases can end only if the disk fills up with swap 
     82 * files, or the amount of free memory remains above the deallocation threshold 
     83 * for an entire cooldown period. 
    8384 * 
    8485 * On the other extreme, Bear phases occur when swapfile allocation fails due 
     
    8687 * space is not likely to satisfy whatever software is using up so much memory 
    8788 * or disk space.  In a Bear phase we assume that the spike in memory usage is a 
    88  * fluke: no more allocations are attempted--probably starving the offending 
     89 * fluke: no more allocations are attempted--hopefully starving the offending 
    8990 * software--and unneeded swap space is freed up more aggressively. 
    9091 * 
    91  * The program's steady state lies between these phases.  Any attempt to 
    92  * allocate a swapfile marks the beginning of either a Bull phase or a Bear 
    93  * phase; the allocation attempt will be given the configured amount of 
    94  * "cooldown time" before the program is allowed to go into the opposite phase. 
    95  * Deallocation does not trigger a transition, though may conceivably provide 
     92 * Deallocation does not trigger a transition, though it may conceivably provide 
    9693 * useful information about optimal phase duration. 
    9794 */ 
     
    158155{ 
    159156  return (clock < cooldown_start + cooldown_time); 
     157} 
     158 
     159 
     160void steady_state(void) 
     161{ 
     162  if (!cooldown_bear) cooldown_start = clock; 
    160163} 
    161164 
     
    248251  static const ssize_t chunk = sizeof(localbuf); 
    249252  ssize_t block = chunk; 
     253 
    250254  /* Zero buffer before using it to write data to swapfile.  This doesn't do 
    251255   * much for security (if an attacker can get to your swapfiles you don't have 
     
    316320  size = MIN(size, max_swapsize); 
    317321 
    318   // TODO: Think about reuse of existing swapfiles 
    319322  unlink(file); 
    320323  const int fd=open(file, O_WRONLY|O_CREAT|O_EXCL|O_LARGEFILE, S_IRUSR|S_IWUSR); 
  • src/swaps.h

    r76 r81  
    6363void free_swapfile(memsize_t maxsize); 
    6464 
     65/// Mark an iteration where we don't want to allocate/deallocate swap files  
     66void steady_state(void); 
     67 
    6568char *set_min_swapsize(long long size); 
    6669char *set_max_swapsize(long long size);