comparison gsm-fw/services/ffs/fsck.c @ 215:517dd86b45b1

gsm-fw/services/ffs: fsck.c compiles
author Michael Spacefalcon <msokolov@ivan.Harhan.ORG>
date Mon, 06 Jan 2014 07:12:02 +0000
parents ef7d7da61c56
children
comparison
equal deleted inserted replaced
214:bdfdea886bea 215:517dd86b45b1
6 * 6 *
7 * $Id: fsck.c 1.3.1.1.1.33 Thu, 08 Jan 2004 15:05:23 +0100 tsj $ 7 * $Id: fsck.c 1.3.1.1.1.33 Thu, 08 Jan 2004 15:05:23 +0100 tsj $
8 * 8 *
9 ******************************************************************************/ 9 ******************************************************************************/
10 10
11 #ifndef TARGET
12 #include "ffs.cfg"
13 #endif
14
15 #include <string.h> 11 #include <string.h>
16 #include <assert.h> 12 #include <assert.h>
17 13
18 #include "ffs/ffs.h" 14 #include "ffs.h"
19 #include "ffs/board/core.h" 15 #include "core.h"
20 #include "ffs/board/drv.h" 16 #include "drv.h"
21 #include "ffs/board/ffstrace.h" 17 #include "ffstrace.h"
22 18
23 /****************************************************************************** 19 /******************************************************************************
24 * Functions 20 * Functions
25 ******************************************************************************/ 21 ******************************************************************************/
26 22
87 83
88 if ((fs.initerror = journal_init(fs.ijournal)) == 0) 84 if ((fs.initerror = journal_init(fs.ijournal)) == 0)
89 break; 85 break;
90 } 86 }
91 87
92 // Init all file_descriptors to zero 88 // Init all file_descriptors to zero
93 memset(fs.fd, 0, sizeof(struct file_descriptor_s) * fs.fd_max); 89 memset(fs.fd, 0, sizeof(struct file_descriptor_s) * fs.fd_max);
94 90
95 // If blocks_fsck() found a block that needs cleaning, we do it, now 91 // If blocks_fsck() found a block that needs cleaning, we do it, now
96 // that all the file system has been initialized. 92 // that all the file system has been initialized.
97 if (b > 0) { 93 if (b > 0) {
98 block_clean(b - 1); 94 block_clean(b - 1);
99 block_free(b - 1); 95 block_free(b - 1);
100 } 96 }
101 97
102 statistics_init(); 98 statistics_init();
103 99
104 // In target, we do this before entering the task event loop... 100 // In target, we do this before entering the task event loop...
122 118
123 void fs_params_init(const char *p) 119 void fs_params_init(const char *p)
124 { 120 {
125 uint8 opt, digit; 121 uint8 opt, digit;
126 uint32 n; 122 uint32 n;
127 int numdatablocks; 123 int numdatablocks;
128 124
129 tw(tr(TR_BEGIN, TrFsck, "fsparams_init('%s') {\n", p)); 125 tw(tr(TR_BEGIN, TrFsck, "fsparams_init('%s') {\n", p));
130 126
131 // Compiled default values 127 // Compiled default values
132 fs.filename_max = FFS_FILENAME_MAX; 128 fs.filename_max = FFS_FILENAME_MAX;
133 fs.path_depth_max = FFS_PATH_DEPTH_MAX; 129 fs.path_depth_max = FFS_PATH_DEPTH_MAX;
134 fs.fd_max = FFS_FD_MAX; 130 fs.fd_max = FFS_FD_MAX;
135 fs.journal_size = FFS_JOURNAL_SIZE_IN256THS; 131 fs.journal_size = FFS_JOURNAL_SIZE_IN256THS;
136 fs.flags = 0; 132 fs.flags = 0;
137 fs.testflags = 0; 133 fs.testflags = 0;
138 134
139 // Flag that it not has been changed by an input arg. 135 // Flag that it not has been changed by an input arg.
140 fs.block_files_max = 0; 136 fs.block_files_max = 0;
141 137
142 // The default lost bytes percentage of a block before it is reclaimed 138 // The default lost bytes percentage of a block before it is reclaimed
143 // is approx. 90%. 139 // is approx. 90%.
144 fs.lost_threshold = (256 - 256/10); 140 fs.lost_threshold = (256 - 256/10);
145 141
146 // If we only have two blocks, we cannot make any reclaims and thus we 142 // If we only have two blocks, we cannot make any reclaims and thus we
147 // have a write-once FFS system. 143 // have a write-once FFS system.
148 fs.blocks_free_min = (dev.numblocks > 2 ? 1 : 0); 144 fs.blocks_free_min = (dev.numblocks > 2 ? 1 : 0);
149 145
150 // Don't count free and inodes blocks 146 // Don't count free and inodes blocks
151 numdatablocks = dev.numblocks - fs.blocks_free_min - 1; 147 numdatablocks = dev.numblocks - fs.blocks_free_min - 1;
152 148
153 // Abselute max number of inodes. 149 // Abselute max number of inodes.
154 fs.inodes_max = dev.blocksize / sizeof(struct inode_s); 150 fs.inodes_max = dev.blocksize / sizeof(struct inode_s);
155 if (fs.inodes_max > FFS_INODES_MAX) 151 if (fs.inodes_max > FFS_INODES_MAX)
156 fs.inodes_max = FFS_INODES_MAX; 152 fs.inodes_max = FFS_INODES_MAX;
157 153
158 // MUST be true: objects_max <= inodes_max - block_files_max, this is do 154 // MUST be true: objects_max <= inodes_max - block_files_max, this is do
159 // to the fact that we always need to have block_files_max number of 155 // to the fact that we always need to have block_files_max number of
160 // inodes left when we run a data reclaim. 156 // inodes left when we run a data reclaim.
161 fs.objects_max = fs.inodes_max / 2; 157 fs.objects_max = fs.inodes_max / 2;
162 158
163 // Find a suitable chunk_size 159 // Find a suitable chunk_size
164 if (dev.numblocks*dev.blocksize > 1024*1024) 160 if (dev.numblocks*dev.blocksize > 1024*1024)
165 fs.chunk_size_max = 8192; 161 fs.chunk_size_max = 8192;
166 else 162 else
167 fs.chunk_size_max = (2048 > (dev.blocksize / 8) 163 fs.chunk_size_max = (2048 > (dev.blocksize / 8)
168 ? (dev.blocksize / 8) 164 ? (dev.blocksize / 8)
169 : 2048); 165 : 2048);
170 fs.fd_buf_size = fs.chunk_size_max; 166 fs.fd_buf_size = fs.chunk_size_max;
171 167
172 fs.journal_size = fs.journal_size * dev.blocksize / 256; 168 fs.journal_size = fs.journal_size * dev.blocksize / 256;
173 if (fs.journal_size < FFS_JOURNAL_SIZE_MIN) 169 if (fs.journal_size < FFS_JOURNAL_SIZE_MIN)
174 fs.journal_size = FFS_JOURNAL_SIZE_MIN; 170 fs.journal_size = FFS_JOURNAL_SIZE_MIN;
175 171
176 // Set it just below the same amount as entries in one journal file 172 // Set it just below the same amount as entries in one journal file
181 // to reach objects_max must block_files_max >= objects_max / number 177 // to reach objects_max must block_files_max >= objects_max / number
182 // of datablocks, however a big block_files_max require higher 178 // of datablocks, however a big block_files_max require higher
183 // reserved_space. 179 // reserved_space.
184 if (fs.block_files_max > fs.objects_max / 2) 180 if (fs.block_files_max > fs.objects_max / 2)
185 fs.block_files_max = fs.objects_max / 2 - 4; 181 fs.block_files_max = fs.objects_max / 2 - 4;
186 182
187 // Are we able to reach objects_max? If not then lower the number 183 // Are we able to reach objects_max? If not then lower the number
188 if (fs.objects_max > numdatablocks * fs.block_files_max) 184 if (fs.objects_max > numdatablocks * fs.block_files_max)
189 fs.objects_max = numdatablocks * fs.block_files_max + 10; 185 fs.objects_max = numdatablocks * fs.block_files_max + 10;
190 186
191 // Absolute minimum is RESERVED_LOW the rest is 'workspace' which is 187 // Absolute minimum is RESERVED_LOW the rest is 'workspace' which is
192 // needed to have a reasonable performance. 188 // needed to have a reasonable performance.
193 fs.reserved_space = dev.blocksize / 2 + 189 fs.reserved_space = dev.blocksize / 2 +
194 numdatablocks * dev.blocksize / 16 + RESERVED_LOW; 190 numdatablocks * dev.blocksize / 16 + RESERVED_LOW;
195 191
196 // skip to first char following second slash in name 192 // skip to first char following second slash in name
197 n = 0; 193 n = 0;
198 while (*p) { 194 while (*p) {
199 if (*p++ == '/') { 195 if (*p++ == '/') {
200 n++; 196 n++;
237 } 233 }
238 } 234 }
239 235
240 // Now recompute a few parameters based on adjusted values. 236 // Now recompute a few parameters based on adjusted values.
241 237
242 // No journal file thuse no reserved space. 238 // No journal file thuse no reserved space.
243 if (fs.journal_size == 0) { 239 if (fs.journal_size == 0) {
244 fs.block_files_max = fs.objects_max / 2; 240 fs.block_files_max = fs.objects_max / 2;
245 fs.reserved_space = 0; 241 fs.reserved_space = 0;
246 fs.block_files_reserved = 0; 242 fs.block_files_reserved = 0;
247 } 243 }
248 244
249 else { 245 else {
250 // If journal size is less than minimum must it have been changed by an 246 // If journal size is less than minimum must it have been changed by an
251 // input arg, recalculate. 247 // input arg, recalculate.
252 if (fs.journal_size < FFS_JOURNAL_SIZE_MIN) 248 if (fs.journal_size < FFS_JOURNAL_SIZE_MIN)
253 fs.journal_size = fs.journal_size * dev.blocksize / 256; 249 fs.journal_size = fs.journal_size * dev.blocksize / 256;
254 250
255 if (fs.reserved_space < RESERVED_LOW) 251 if (fs.reserved_space < RESERVED_LOW)
256 fs.reserved_space = fs.reserved_space * dev.blocksize / 256; 252 fs.reserved_space = fs.reserved_space * dev.blocksize / 256;
257 253
258 // Only one reserved is needed however we want a margin and set it to two 254 // Only one reserved is needed however we want a margin and set it to 2
259 fs.block_files_reserved = 2; 255 fs.block_files_reserved = 2;
260 } 256 }
261 257
262 // Don't count free blocks, inode block, reserved space, block headers 258 // Don't count free blocks, inode block, reserved space, block headers
263 // and the size of one filename. 259 // and the size of one filename.
264 fs.filesize_max = numdatablocks * dev.blocksize - fs.reserved_space - 260 fs.filesize_max = numdatablocks * dev.blocksize - fs.reserved_space -
265 numdatablocks * BHEADER_SIZE - FFS_FILENAME_MAX; 261 numdatablocks * BHEADER_SIZE - FFS_FILENAME_MAX;
266 262
267 // Furthermore don't count the overhead from each chunk (alignment) 263 // Furthermore don't count the overhead from each chunk (alignment)
268 fs.filesize_max -= ((fs.filesize_max / fs.chunk_size_max) * dev.atomsize 264 fs.filesize_max -= ((fs.filesize_max / fs.chunk_size_max) * dev.atomsize
269 + dev.atomsize); 265 + dev.atomsize);
270 266
271 // NOTEME: chunk_size_min is never used 267 // NOTEME: chunk_size_min is never used
272 fs.chunk_size_min = numdatablocks / fs.objects_max; 268 fs.chunk_size_min = numdatablocks / fs.objects_max;
273 269
274 tw(tr(TR_FUNC, TrFsck, "dev.numblocks = %d\n", dev.numblocks)); 270 tw(tr(TR_FUNC, TrFsck, "dev.numblocks = %d\n", dev.numblocks));
275 tw(tr(TR_FUNC, TrFsck, "fs.blocks_free_min = %d\n", fs.blocks_free_min)); 271 tw(tr(TR_FUNC, TrFsck, "fs.blocks_free_min = %d\n", fs.blocks_free_min));
276 tw(tr(TR_FUNC, TrFsck, "fs.inodes_max = %d\n", fs.inodes_max)); 272 tw(tr(TR_FUNC, TrFsck, "fs.inodes_max = %d\n", fs.inodes_max));
277 tw(tr(TR_FUNC, TrFsck, "fs.objects_max = %d\n", fs.objects_max)); 273 tw(tr(TR_FUNC, TrFsck, "fs.objects_max = %d\n", fs.objects_max));
278 tw(tr(TR_FUNC, TrFsck, "fs.block_files_max = %d\n", fs.block_files_max)); 274 tw(tr(TR_FUNC, TrFsck, "fs.block_files_max = %d\n", fs.block_files_max));
279 tw(tr(TR_FUNC, TrFsck, "fs.block_files_reserved = %d\n", fs.block_files_reserved)); 275 tw(tr(TR_FUNC, TrFsck, "fs.block_files_reserved = %d\n", fs.block_files_reserved));
280 tw(tr(TR_FUNC, TrFsck, "fs.chunk_size_max = %d\n", fs.chunk_size_max)); 276 tw(tr(TR_FUNC, TrFsck, "fs.chunk_size_max = %d\n", fs.chunk_size_max));
281 tw(tr(TR_FUNC, TrFsck, "fs.filename_max = %d\n", fs.filename_max)); 277 tw(tr(TR_FUNC, TrFsck, "fs.filename_max = %d\n", fs.filename_max));
282 tw(tr(TR_FUNC, TrFsck, "fs.lost_threshold = %d\n", fs.lost_threshold)); 278 tw(tr(TR_FUNC, TrFsck, "fs.lost_threshold = %d\n", fs.lost_threshold));
283 tw(tr(TR_FUNC, TrFsck, "fs.path_depth_max = %d\n", fs.path_depth_max)); 279 tw(tr(TR_FUNC, TrFsck, "fs.path_depth_max = %d\n", fs.path_depth_max));
284 tw(tr(TR_FUNC, TrFsck, "fs.journal_size = %d\n", fs.journal_size)); 280 tw(tr(TR_FUNC, TrFsck, "fs.journal_size = %d\n", fs.journal_size));
339 { 335 {
340 blocksize_t used; 336 blocksize_t used;
341 uint32 *p, *q; 337 uint32 *p, *q;
342 338
343 tlw(led_toggle(LED_BLOCKS_FSCK)); 339 tlw(led_toggle(LED_BLOCKS_FSCK));
344 340
345 // We search backwards through block to find the last used byte and 341 // We search backwards through block to find the last used byte and
346 // thus the total number of used bytes. Note that this code depends 342 // thus the total number of used bytes. Note that this code depends
347 // on the fact that an erased flash location is 0xFF! 343 // on the fact that an erased flash location is 0xFF!
348 p = (uint32 *) offset2addr(dev.binfo[b].offset); 344 p = (uint32 *) offset2addr(dev.binfo[b].offset);
349 for (q = p + dev.blocksize/4 - 4; q > p; q -= 4) { 345 for (q = p + dev.blocksize/4 - 4; q > p; q -= 4) {
382 // has been properly intialized (we actually return the block number + 1 378 // has been properly intialized (we actually return the block number + 1
383 // because otherwise it would clash with EFFS_OK return code). If no inodes 379 // because otherwise it would clash with EFFS_OK return code). If no inodes
384 // block is found or another error occurs, we return the error code. 380 // block is found or another error occurs, we return the error code.
385 bref_t blocks_fsck(void) 381 bref_t blocks_fsck(void)
386 { 382 {
387 bref_t b, b_to_clean, b_inode_lost; 383 bref_t b, b_to_clean, b_inode_lost;
388 int age_valid; 384 int age_valid;
389 age_t age_min, age_max, age_dist, age_dist_min, age_dist_max; 385 age_t age_min, age_max, age_dist, age_dist_min, age_dist_max;
390 struct block_header_s *bhp; 386 struct block_header_s *bhp;
391 struct block_header_old_s *obhp; 387 struct block_header_old_s *obhp;
392 388
397 age_min = age_max = age_dist = 0; 393 age_min = age_max = age_dist = 0;
398 394
399 fs.format = 0; 395 fs.format = 0;
400 fs.inodes = -1; 396 fs.inodes = -1;
401 fs.newinodes = -1; 397 fs.newinodes = -1;
402 b_inode_lost = -1; 398 b_inode_lost = -1;
403 b_to_clean = EFFS_OK; 399 b_to_clean = EFFS_OK;
404 400
405 for (b = 0; b < dev.numblocks; b++) 401 for (b = 0; b < dev.numblocks; b++)
406 { 402 {
407 tlw(led_toggle(LED_DRV_INIT)); 403 tlw(led_toggle(LED_DRV_INIT));
569 tw(tr(TR_FUNC, TrFsck, "fs.inodes, newinodes = %d, %d\n", 565 tw(tr(TR_FUNC, TrFsck, "fs.inodes, newinodes = %d, %d\n",
570 fs.inodes, fs.newinodes)); 566 fs.inodes, fs.newinodes));
571 ttw(ttr(TTrInit, "fs.inodes, newinodes = %d, %d" NL, 567 ttw(ttr(TTrInit, "fs.inodes, newinodes = %d, %d" NL,
572 fs.inodes, fs.newinodes)); 568 fs.inodes, fs.newinodes));
573 tw(tr(TR_FUNC, TrFsck, "age min, max = %d, %d\n", age_min, age_max)); 569 tw(tr(TR_FUNC, TrFsck, "age min, max = %d, %d\n", age_min, age_max));
574 570
575 // If any blocks were in the EMPTY state, now is the time to bring them 571 // If any blocks were in the EMPTY state, now is the time to bring them
576 // into the FREE state. Note that we must only do this *after* 572 // into the FREE state. Note that we must only do this *after*
577 // fs.age_max has been initialized. 573 // fs.age_max has been initialized.
578 for (b = 0; b < dev.numblocks; b++) { 574 for (b = 0; b < dev.numblocks; b++) {
579 if (is_block(b, BF_IS_EMPTY)) { 575 if (is_block(b, BF_IS_EMPTY)) {
582 else 578 else
583 block_free(b); 579 block_free(b);
584 } 580 }
585 } 581 }
586 582
587 if (fs.inodes >= 0) { 583 if (fs.inodes >= 0) {
588 // The 'old' inode block is still valid thus we keep it. 584 // The 'old' inode block is still valid thus we keep it.
589 if (fs.newinodes >= 0) 585 if (fs.newinodes >= 0)
590 // The copying of inodes to the new block was not finished thus 586 // The copying of inodes to the new block was not finished thus
591 // we free the block 587 // we free the block
592 block_free(fs.newinodes); 588 block_free(fs.newinodes);
593 inodes_set(fs.inodes); 589 inodes_set(fs.inodes);
594 } 590 }
595 else { 591 else {
596 // Copying must have been finished 592 // Copying must have been finished
597 if (fs.newinodes >= 0 && b_inode_lost >= 0) { 593 if (fs.newinodes >= 0 && b_inode_lost >= 0) {
598 // The inode reclaim did finish but currently there is no valid 594 // The inode reclaim did finish but currently there is no valid
599 // inode block thus the operation must be finished by committing 595 // inode block thus the operation must be finished by committing
600 // the new block as the valid inode block. 596 // the new block as the valid inode block.
601 fs.inodes = b_inode_lost; 597 fs.inodes = b_inode_lost;
602 block_commit(); 598 block_commit();
603 599 }
604 } 600 else {
605 else {
606 // No old or new Inode block! 601 // No old or new Inode block!
607 tw(tr(TR_END, TrFsck, "} %d\n", EFFS_NOFORMAT)); 602 tw(tr(TR_END, TrFsck, "} %d\n", EFFS_NOFORMAT));
608 ttw(ttr(TTrInitLow, "} %d" NL, EFFS_NOFORMAT)); 603 ttw(ttr(TTrInitLow, "} %d" NL, EFFS_NOFORMAT));
609 return EFFS_NOFORMAT; 604 return EFFS_NOFORMAT;
610 }
611 } 605 }
612 606 }
607
613 if ((fs.format >> 8) != (FFS_FORMAT_VERSION >> 8)) { 608 if ((fs.format >> 8) != (FFS_FORMAT_VERSION >> 8)) {
614 tw(tr(TR_END, TrFsck, "} %d\n", EFFS_BADFORMAT)); 609 tw(tr(TR_END, TrFsck, "} %d\n", EFFS_BADFORMAT));
615 ttw(ttr(TTrInitLow, "} %d" NL, EFFS_BADFORMAT)); 610 ttw(ttr(TTrInitLow, "} %d" NL, EFFS_BADFORMAT));
616 return EFFS_BADFORMAT; 611 return EFFS_BADFORMAT;
617 } 612 }
1083 fs.journal_pos += sizeof(struct journal_s); 1078 fs.journal_pos += sizeof(struct journal_s);
1084 1079
1085 // Unless we are currently relocating the journal file itself, check if 1080 // Unless we are currently relocating the journal file itself, check if
1086 // journal file is near full and relocate it if it is. 1081 // journal file is near full and relocate it if it is.
1087 if (fs.journal_pos >= fs.journal_size - FFS_JOURNAL_MARGIN * 1082 if (fs.journal_pos >= fs.journal_size - FFS_JOURNAL_MARGIN *
1088 sizeof(struct journal_s) && fs.journal.oldi != fs.ijournal) { 1083 sizeof(struct journal_s) && fs.journal.oldi != fs.ijournal) {
1089 tw(tr(TR_FUNC, TrJournal, "Journal file (near) full!\n")); 1084 tw(tr(TR_FUNC, TrJournal, "Journal file (near) full!\n"));
1090 journal_create(fs.ijournal); 1085 journal_create(fs.ijournal);
1091 } 1086 }
1092 1087
1093 // Check if we have just committed the journal file itself 1088 // Check if we have just committed the journal file itself
1212 memcpy(&fs.ojournal, &fs.journal, sizeof(struct journal_s)); 1207 memcpy(&fs.ojournal, &fs.journal, sizeof(struct journal_s));
1213 fs.journal_depth++; 1208 fs.journal_depth++;
1214 if (fs.journal_depth > 1) { 1209 if (fs.journal_depth > 1) {
1215 tw(tr(TR_FUNC, TrAll, "FATAL: journal_push() to depth %d\n", 1210 tw(tr(TR_FUNC, TrAll, "FATAL: journal_push() to depth %d\n",
1216 fs.journal_depth)); 1211 fs.journal_depth));
1217 return -1; 1212 return -1;
1218 } 1213 }
1219 1214
1220 tw(tr(TR_FUNC, TrJournal, "journal_push() to depth %d\n", 1215 tw(tr(TR_FUNC, TrJournal, "journal_push() to depth %d\n",
1221 fs.journal_depth)); 1216 fs.journal_depth));
1222 1217
1223 return EFFS_OK; 1218 return EFFS_OK;
1224 } 1219 }
1225 1220
1226 // Recall "old" journal into current journal 1221 // Recall "old" journal into current journal
1227 int journal_pop(void) 1222 int journal_pop(void)
1228 { 1223 {
1231 1226
1232 fs.journal_depth--; 1227 fs.journal_depth--;
1233 if (fs.journal_depth < 0) { 1228 if (fs.journal_depth < 0) {
1234 tw(tr(TR_FUNC, TrAll, "FATAL: journal_pop() to depth %d\n", 1229 tw(tr(TR_FUNC, TrAll, "FATAL: journal_pop() to depth %d\n",
1235 fs.journal_depth)); 1230 fs.journal_depth));
1236 return -1; 1231 return -1;
1237 } 1232 }
1238 memcpy(&fs.journal, &fs.ojournal, sizeof(struct journal_s)); 1233 memcpy(&fs.journal, &fs.ojournal, sizeof(struct journal_s));
1239 1234
1240 return EFFS_OK; 1235 return EFFS_OK;
1241 } 1236 }
1242 1237
1243 // Initialize the journalling system. Create journal file if it not already 1238 // Initialize the journalling system. Create journal file if it not already
1244 // exist. Commit/write pending journal if such exists --- return 1 in that 1239 // exist. Commit/write pending journal if such exists --- return 1 in that
1245 // case. Otherwise, if journal file is clean (no journals pending) and all 1240 // case. Otherwise, if journal file is clean (no journals pending) and all
1439 1434
1440 // Read the statistics file if it exists. Otherwise reset all statistics to 1435 // Read the statistics file if it exists. Otherwise reset all statistics to
1441 // zero and set the magic. This function is called from ffs_init(). 1436 // zero and set the magic. This function is called from ffs_init().
1442 void statistics_init(void) 1437 void statistics_init(void)
1443 { 1438 {
1444 memset(&stats, 0, sizeof(struct ffs_stats_s)); 1439 memset(&stats, 0, sizeof(struct ffs_stats_s));
1445 } 1440 }
1446 1441
1447 void statistics_update_drec(int valid, int lost, int candidate) 1442 void statistics_update_drec(int valid, int lost, int candidate)
1448 { 1443 {
1449 unsigned int old; 1444 unsigned int old;
1470 { 1465 {
1471 stats.irec.num++; 1466 stats.irec.num++;
1472 stats.irec.valid += valid; 1467 stats.irec.valid += valid;
1473 stats.irec.lost += lost; 1468 stats.irec.lost += lost;
1474 } 1469 }
1475