Changeset 76
- Timestamp:
- 05/31/05 00:59:47 (4 years ago)
- Files:
-
- TODO (modified) (1 diff)
- debian/changelog (modified) (1 diff)
- src/Makefile (modified) (2 diffs)
- src/log.c (modified) (3 diffs)
- src/log.h (modified) (1 diff)
- src/main.c (modified) (4 diffs)
- src/memory.c (modified) (10 diffs)
- src/memory.h (modified) (1 diff)
- src/opts.c (modified) (1 diff)
- src/swaps.c (modified) (23 diffs)
- src/swaps.h (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
TODO
r72 r76 1 Policy 2 - Stabilize behaviour of that very first swapfile (allocate small "zero" file?) 1 Error Reporting 2 - Unify logging/printing code: print-only or dynamic choice 3 - Ensure minimal repetition of error/warning messages 3 4 4 Prettiness5 - Unify logging/printing code: print-only or dynamic choice6 5 6 Policy Weaknesses 7 8 Current policy is a bit weak when it comes to filesystem caching. The problem 9 is that cache populations grow and grow until they hit the limit of available 10 physical memory--creating an arguably false impression of memory shortage. The 11 flexibility of the Linux virtual memory subsystem makes this, as far as I can 12 see at this stage, impossible to diagnose directly. 13 14 Most noticeable symptom: existing swapfiles are freed up sometime between system 15 boot (when little data is cached and most physical memory is still free) and the 16 moment when ever-growing caches push the percentage of free memory below our 17 daemon's allocation threshold. We end up allocating a new swapfile shortly 18 after deallocating our last one, just as the user is getting into the swing of 19 things and expects his system to respond smoothly. While we're setting up that 20 new swapfile, it doesn't. This is hard to anticipate; starting up in bull mode 21 may help as a practical matter by deferring the decision to deallocate, but 22 only if the associated cooldown period is long enough for filesystem caches to 23 fill up again and bring the system into a "steady state." 24 25 There are other cases that can trigger this behaviour, though. Consider this 26 situation: some application X eats up huge amounts of virtual memory, most of 27 which is in active use and therefore resides in physical memory. Swap is full 28 of rarely-used virtual memory pages. Little or no filesystem caching occurs. 29 Next, X finishes and suddenly we have lots of free physical memory--although 30 swap remains densely populated. I'll need to do some math (probably quite 31 simple, once I have the right formula) to figure out what can and cannot happen 32 here. 33 34 Scenario A: if most of the swapped-out data is touched again before we go into 35 bear mode and consider deallocating, we're fine. We'll end up freeing largely 36 unused swap space. 37 38 Scenario B: if swap is deallocated at this stage, any remaining data it held 39 will have to be read back in a hurry--plus, continued system operation may be 40 suboptimal because some of that data is "colder" than filesystem data that could 41 have been cached in the physical memory that X left free in its wake. 42 43 Scenario C: if the "data vacuum" left by X is filled up by filesystem caches, we 44 may end up thinking (once again) that we're short on memory--and allocating swap 45 space that we won't be needing at all. Bull mode will be prolonged when a 46 return to bear mode is in order. 47 48 One consolation: since filesystem caches are never swapped to disk, they cannot 49 exceed physical memory size. This means that the algorithm, for any acceptable 50 set of parameters, can "overshoot" by at most a single swapfile. 51 52 We could try to distinguish "false shortages" from real memory needs by 53 ensuring that there is some "tripwire swap"--perhaps an existing conventional 54 swap partition, or a special swapfile numbered zero. An increase in the 55 population of this swap would indicate true memory shortage. The only problem 56 is that the system may not resort to using the tripwire swap until it is already 57 desperate! Can we set a positive priority to make the tripwire slightly more 58 sensitive? We'd also have to clean this file up from time to time, because once 59 it fills up the mechanism breaks down. 60 61 62 Bull/Bear Mode 63 64 Currently, the program goes into bear mode if swapfile allocation fails and into 65 bull mode when swapfiles are allocated. In the steady state we're somewhere 66 inbetween. Maybe this isn't the best way to do it. 67 68 What if we inhibited deallocations not just in bull mode, but instead required 69 that the percentage of available space was above the deallocation limit for an 70 entire cooldown period? 71 debian/changelog
r75 r76 1 swapspace (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 1 12 swapspace (1.2) unstable; urgency=low 2 13 3 14 * Initial Debian package. 4 15 5 -- Jeroen T. Vermeulen <jtv@sipa.or.th> Fr y, 20 May 2005 14:00:00 +070016 -- Jeroen T. Vermeulen <jtv@sipa.or.th> Fri, 20 May 2005 14:00:00 +0700 6 17 src/Makefile
r59 r76 16 16 hog : hog.o 17 17 18 log.o : log.c log.h main.h 18 log.o : log.c log.h main.h memory.h 19 19 20 main.o : main.c config.h env.h main.h memory.h support.h20 main.o : main.c config.h env.h log.h main.h memory.h support.h 21 21 22 memory.o : memory.c config.h env.h main.h memory.h support.h22 memory.o : memory.c config.h env.h log.h main.h memory.h support.h 23 23 24 24 opts.o : opts.c opts.h main.h … … 26 26 support.o : support.c config.h env.h support.h 27 27 28 swaps.o : swaps.c config.h env.h support.h swaps.h28 swaps.o : swaps.c config.h env.h log.h main.h memory.h support.h swaps.h 29 29 30 30 clean : src/log.c
r59 r76 16 16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 17 */ 18 #include <errno.h> 19 #include <stdio.h> 20 #include <string.h> 21 18 22 #include "log.h" 19 23 20 24 static bool logging = false; 21 22 25 23 26 #ifndef LOG_PERROR … … 37 40 38 41 39 bool am_logging(void)40 {41 return logging;42 }43 44 45 42 /// Stop logging, e.g. because storage containing log name goes out of scope 46 43 void log_close() … … 50 47 } 51 48 49 50 static 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 62 static 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 74 void 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 81 void log_perr(int priority, const char msg[]) 82 { 83 log_perrno(priority, msg, errno); 84 } 85 86 87 void 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 100 void 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 107 void 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 125 void 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 132 void 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 22 22 23 23 #include "main.h" 24 #include "memory.h" 24 25 25 26 /// Open log, with given program name (string storage must remain available!) 26 27 void log_start(const char myname[]); 27 28 28 /// Has logging been enabled? If not, try writing any messages to stderr29 bool am_logging(void);30 31 29 /// Stop logging, e.g. because storage containing log name goes out of scope 32 30 void log_close(); 33 31 32 /// Write plain message to log, or standard output/error as appropriate 33 void log_msg(int priority, const char msg[]); 34 35 /// Log plain message followed by quoted string 36 void log_str(int priority, const char msg[], const char arg[]); 37 38 /// Log message in perror() style (i.e. with errno-based message appended) 39 void log_perr(int priority, const char msg[]); 40 41 /// Log message with given errno (or ignore error number if it is zero) 42 void log_perrno(int priority, const char msg[], int fault_errno); 43 44 /// Log message, perror()-style, but appending a quoted string 45 void log_perr_str(int priority, const char msg[], const char arg[]); 46 47 /// Log message, but appending an integer argument 48 void log_int(int priority, const char msg[], int arg); 49 50 /// Log logfile size discrepancy 51 void log_discrep(int priority, 52 const char msg[], 53 int swapfile, 54 memsize_t expected, 55 memsize_t found); 56 34 57 #endif 35 58 src/main.c
r59 r76 78 78 static volatile bool print_status=false; 79 79 80 /// Was an immediate adjustment requested? 80 81 static volatile bool adjust_swap=false; 81 82 … … 94 95 if (unlikely(write(pidfd, localbuf, len) < len)) 95 96 { 96 fprintf(stderr, "Could not write pidfile %s: %s\n",pidfile,strerror(errno));97 log_perr_str(LOG_ERR, "Could not write pidfile", pidfile); 97 98 return false; 98 99 } … … 114 115 if (unlikely(pidfd == -1)) 115 116 { 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); 121 119 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); 126 121 return false; 127 122 } … … 207 202 static void handle_requirements(void) 208 203 { 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); 213 207 } 214 208 src/memory.c
r59 r76 39 39 static int freetarget=25; 40 40 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"? 43 static int cache_meekness=50; 44 41 45 char *set_freetarget(long long pct) 42 46 { … … 56 60 return NULL; 57 61 } 62 63 char *set_cache_meekness(long long pct) 64 { 65 cache_meekness = (int)pct; 66 return NULL; 67 } 68 58 69 59 70 bool memory_check_config(void) … … 147 158 memsize_t MemTotal, 148 159 MemFree, 160 Cached, 161 Dirty, 162 Writeback, 163 SwapCached, 149 164 SwapTotal, 150 165 SwapFree; … … 156 171 switch (inf->entry[0]) 157 172 { 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; 158 179 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 } 161 185 break; 162 186 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; 165 196 break; 166 197 } … … 173 204 if (unlikely(!fp)) 174 205 { 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"); 179 207 return false; 180 208 } … … 183 211 while (read_meminfo_item(fp, &inf)) imbibe_meminfo_entry(&inf, result); 184 212 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); 198 214 199 215 return true; … … 207 223 { 208 224 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); 210 226 else if (init_req < 0) printf("%lld bytes to spare\n", -init_req); 211 227 } … … 214 230 215 231 232 /// How much cache space can we expect the system to free up? 233 static 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 216 240 static inline memsize_t space_free(const struct memstate *st) 217 241 { 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); 219 268 } 220 269 … … 241 290 assert(upper_freelimit > lower_freelimit); 242 291 243 struct memstate st = { 0, 0, 0, 0 };292 struct memstate st = { 0, 0, 0, 0, 0, 0, 0, 0 }; 244 293 if (unlikely(!read_proc_meminfo(&st))) return MEMSIZE_ERROR; 245 294 … … 248 297 249 298 // 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? 251 300 if (freepct < lower_freelimit || freepct > upper_freelimit) 252 301 { src/memory.h
r59 r76 40 40 char *set_upper_freelimit(long long pct); 41 41 char *set_freetarget(long long pct); 42 char *set_cache_meekness(long long pct); 42 43 43 44 bool memory_check_config(void); src/opts.c
r59 r76 61 61 static const struct option options[] = 62 62 { 63 { "cache_meekness", 'w', at_num, 0, 100, set_cache_meekness, 64 "Consider n% of cache memory to be free space" }, 63 65 { "configfile", 'c', at_str, 1, PATH_MAX, set_configfile, 64 66 "Use configuration file s" }, src/swaps.c
r72 r76 61 61 62 62 /// Smallest allowed swapfile size 63 static memsize_t min_swapsize = 12*PAGE_SIZE;63 static memsize_t min_swapsize = (12*PAGE_SIZE) & PAGE_MASK; 64 64 /// Largest allowed swapfile size 65 65 /** Don't set this too low. The program will learn if it runs into file size 66 66 * limits. 67 67 */ 68 static memsize_t max_swapsize = TERA ;68 static memsize_t max_swapsize = TERA & PAGE_MASK; 69 69 70 70 … … 100 100 char *set_min_swapsize(long long size) 101 101 { 102 min_swapsize = ( memsize_t)size;102 min_swapsize = ((memsize_t)size & PAGE_MASK); 103 103 return NULL; 104 104 } … … 106 106 char *set_max_swapsize(long long size) 107 107 { 108 max_swapsize = ( memsize_t)size;108 max_swapsize = ((memsize_t)size) & PAGE_MASK; 109 109 return NULL; 110 110 } … … 119 119 bool swaps_check_config(void) 120 120 { 121 assert(!am_logging());122 121 CHECK_CONFIG_ERR(min_swapsize > max_swapsize); 123 122 124 123 if (chdir(swappath) == -1) 125 124 { 126 fprintf(stderr, "Could not cd to %s: %s\n", swappath, strerror(errno));125 log_perr_str(LOG_ERR, "Coult not cd to", swappath); 127 126 return false; 128 127 } 129 128 if (!getcwd(swappath, sizeof(swappath))) 130 129 { 131 fputs("Swap path too long\n", stderr);130 log_msg(LOG_ERR, "Swap path too long"); 132 131 return false; 133 132 } … … 141 140 for (int i=swappath_len-1; i >= 0; --i) if (isspace(swappath[i])) 142 141 { 143 fputs("Not supported: swap path contains whitespace\n", stderr);142 log_msg(LOG_ERR, "Not supported: swap path contains whitespace"); 144 143 return false; 145 144 } … … 235 234 runcommand("mkswap", file); 236 235 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); 242 237 return ok; 243 238 } … … 270 265 { 271 266 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); 274 268 bytes -= block; 275 269 switch (err) … … 277 271 case EFBIG: 278 272 // 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); 280 275 break; 281 276 case ENOSPC: … … 299 294 /** 300 295 * @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) 303 297 * @return Size of new swapfile, which may differ from requested size. Zero or 304 298 * less indicates failure, in which case the file is deleted. Negative result … … 306 300 * likely to be appreciated. 307 301 */ 308 static memsize_t make_swapfile(const char file[], memsize_t size , memsize_t min)302 static memsize_t make_swapfile(const char file[], memsize_t size) 309 303 { 310 304 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; 311 312 312 313 // Don't allocate swap for a while--we had a bad experience recently 313 314 if (unlikely(cooldown_bear) && in_cooldown()) return 0; 314 315 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); 319 317 320 318 // TODO: Think about reuse of existing swapfiles … … 323 321 if (unlikely(fd == -1)) 324 322 { 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); 332 324 return 0; 333 325 } 334 size = fill_swapfile(fd, size);326 realsize = fill_swapfile(fd, size); 335 327 close(fd); 336 if (unlikely( size < min))328 if (unlikely(realsize < size)) 337 329 { 338 330 unlink(file); … … 340 332 } 341 333 342 return size;334 return realsize; 343 335 } 344 336 … … 371 363 if (unlikely(fd == -1)) 372 364 { 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); 377 366 return -1; 378 367 } 368 379 369 memsize_t pos = SEEK(fd, 0, SEEK_END); 380 370 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 387 373 return pos; 388 374 } … … 391 377 bool activate_old_swaps(void) 392 378 { 393 assert(!am_logging());394 395 379 DIR *dir = opendir("."); 396 380 if (unlikely(!dir)) 397 381 { 398 perror("Cannot read swap directory");382 log_perr(LOG_ERR, "Cannot read swap directory"); 399 383 return false; 400 384 } … … 404 388 if (valid_swapfile(d->d_name, &seqno) && !swapfiles[seqno].size) 405 389 { 406 if (!quiet) printf("Found old swapfile %d\n", seqno);390 if (!quiet) log_int(LOG_INFO, "Found old swapfile", seqno); 407 391 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))) 409 393 { 410 394 swapfiles[seqno].size = size; … … 412 396 else 413 397 { 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); 415 399 unlink(d->d_name); 416 400 } … … 428 412 { 429 413 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"); 435 415 return fp; 436 416 } … … 443 423 if (unlikely(sscanf(localbuf, "Filename Type Size Used %c",&c) < 1)) 444 424 { 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"); 446 426 return false; 447 427 } … … 488 468 * somewhere further down. 489 469 */ 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 } 496 475 } 497 476 // /proc/swaps appears to report sizes in 1 KB blocks … … 507 486 { 508 487 // 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); 516 489 swapfiles[result->seqno].created = clock; 517 490 } … … 522 495 const memsize_t expected = swapfiles[result->seqno].size, 523 496 found = result->size; 524 const char *notice = NULL; 525 bool serious = false; 497 526 498 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); 531 500 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); 535 506 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); 558 512 } 559 513 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 573 520 swapfiles[result->seqno].size = result->size; 574 521 swapfiles[result->seqno].used = result->used; … … 617 564 * they are still in use or things would get horribly confused. 618 565 */ 619 if (!quiet)620 {621 if (am_logging()) syslog(LOG_INFO, "Retiring swapfile %d", file);622 else printf("Retiring swapfile %d\n",file);623 }624 566 char namebuf[30]; 625 567 snprintf(namebuf, sizeof(namebuf), "%d", file); 568 if (!quiet) log_str(LOG_NOTICE, "Retiring swapfile", namebuf); 626 569 if (unlikely(swapoff(namebuf) == -1)) return false; 627 570 swapfiles[file].size = 0; … … 668 611 669 612 670 // TODO: Do away with the "required" option. Disk full means failure, period. 671 void alloc_swapfile(memsize_t requested, memsize_t required) 613 void alloc_swapfile(memsize_t size) 672 614 { 673 615 /* Round request to page size, then add a bit for swapfile overhead. Clever 674 616 * readers will notice that this relies on PAGE_SIZE being a power of two. 675 617 */ 676 requested = (requested & ~(PAGE_SIZE-1)) + 2*PAGE_SIZE;618 size = (size & PAGE_MASK) + 2*PAGE_SIZE; 677 619 const int newswap = find_free(sequence_number); 678 620 if (swapfiles[newswap].size) return; // No free slot, sorry! 679 621 680 622 // We can allocate another swapfile. Great. 623 if (!quiet) log_int(LOG_NOTICE, "Allocating swapfile", newswap); 681 624 char file[30]; 682 625 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); 697 627 698 628 if (swapfiles[newswap].size) src/swaps.h
r59 r76 53 53 /// Create a new swapfile. Clobbers localbuf. 54 54 /** 55 * @param requested target size for new swapfile 56 * @param required minimum size for new swapfile 55 * @param size number of bytes to allocate 57 56 */ 58 void alloc_swapfile(memsize_t requested, memsize_t required);57 void alloc_swapfile(memsize_t size); 59 58 60 59 /// Free swap space
