@@ -129,6 +129,8 @@ int lfs_emubd_create(const struct lfs_config *cfg,
129
129
bd -> proged = 0 ;
130
130
bd -> erased = 0 ;
131
131
bd -> power_cycles = bd -> cfg -> power_cycles ;
132
+ bd -> ooo_block = -1 ;
133
+ bd -> ooo_data = NULL ;
132
134
bd -> disk = NULL ;
133
135
134
136
if (bd -> cfg -> disk_path ) {
@@ -195,6 +197,7 @@ int lfs_emubd_destroy(const struct lfs_config *cfg) {
195
197
free (bd -> blocks );
196
198
197
199
// clean up other resources
200
+ lfs_emubd_decblock (bd -> ooo_data );
198
201
if (bd -> disk ) {
199
202
bd -> disk -> rc -= 1 ;
200
203
if (bd -> disk -> rc == 0 ) {
@@ -209,6 +212,75 @@ int lfs_emubd_destroy(const struct lfs_config *cfg) {
209
212
}
210
213
211
214
215
+ // powerloss hook
216
+ static int lfs_emubd_powerloss (const struct lfs_config * cfg ) {
217
+ lfs_emubd_t * bd = cfg -> context ;
218
+
219
+ // emulate out-of-order writes?
220
+ lfs_emubd_block_t * ooo_data = NULL ;
221
+ if (bd -> cfg -> powerloss_behavior == LFS_EMUBD_POWERLOSS_OOO
222
+ && bd -> ooo_block != -1 ) {
223
+ // since writes between syncs are allowed to be out-of-order, it
224
+ // shouldn't hurt to restore the first write on powerloss, right?
225
+ ooo_data = bd -> blocks [bd -> ooo_block ];
226
+ bd -> blocks [bd -> ooo_block ] = lfs_emubd_incblock (bd -> ooo_data );
227
+
228
+ // mirror to disk file?
229
+ if (bd -> disk
230
+ && (bd -> blocks [bd -> ooo_block ]
231
+ || bd -> cfg -> erase_value != -1 )) {
232
+ off_t res1 = lseek (bd -> disk -> fd ,
233
+ (off_t )bd -> ooo_block * bd -> cfg -> erase_size ,
234
+ SEEK_SET );
235
+ if (res1 < 0 ) {
236
+ return - errno ;
237
+ }
238
+
239
+ ssize_t res2 = write (bd -> disk -> fd ,
240
+ (bd -> blocks [bd -> ooo_block ])
241
+ ? bd -> blocks [bd -> ooo_block ]-> data
242
+ : bd -> disk -> scratch ,
243
+ bd -> cfg -> erase_size );
244
+ if (res2 < 0 ) {
245
+ return - errno ;
246
+ }
247
+ }
248
+ }
249
+
250
+ // simulate power loss
251
+ bd -> cfg -> powerloss_cb (bd -> cfg -> powerloss_data );
252
+
253
+ // if we continue, undo out-of-order write emulation
254
+ if (bd -> cfg -> powerloss_behavior == LFS_EMUBD_POWERLOSS_OOO
255
+ && bd -> ooo_block != -1 ) {
256
+ lfs_emubd_decblock (bd -> blocks [bd -> ooo_block ]);
257
+ bd -> blocks [bd -> ooo_block ] = ooo_data ;
258
+
259
+ // mirror to disk file?
260
+ if (bd -> disk
261
+ && (bd -> blocks [bd -> ooo_block ]
262
+ || bd -> cfg -> erase_value != -1 )) {
263
+ off_t res1 = lseek (bd -> disk -> fd ,
264
+ (off_t )bd -> ooo_block * bd -> cfg -> erase_size ,
265
+ SEEK_SET );
266
+ if (res1 < 0 ) {
267
+ return - errno ;
268
+ }
269
+
270
+ ssize_t res2 = write (bd -> disk -> fd ,
271
+ (bd -> blocks [bd -> ooo_block ])
272
+ ? bd -> blocks [bd -> ooo_block ]-> data
273
+ : bd -> disk -> scratch ,
274
+ bd -> cfg -> erase_size );
275
+ if (res2 < 0 ) {
276
+ return - errno ;
277
+ }
278
+ }
279
+ }
280
+
281
+ return 0 ;
282
+ }
283
+
212
284
213
285
// block device API
214
286
@@ -344,8 +416,11 @@ int lfs_emubd_prog(const struct lfs_config *cfg, lfs_block_t block,
344
416
if (bd -> power_cycles > 0 ) {
345
417
bd -> power_cycles -= 1 ;
346
418
if (bd -> power_cycles == 0 ) {
347
- // simulate power loss
348
- bd -> cfg -> powerloss_cb (bd -> cfg -> powerloss_data );
419
+ int err = lfs_emubd_powerloss (cfg );
420
+ if (err ) {
421
+ LFS_EMUBD_TRACE ("lfs_emubd_prog -> %d" , err );
422
+ return err ;
423
+ }
349
424
}
350
425
}
351
426
@@ -361,10 +436,17 @@ int lfs_emubd_erase(const struct lfs_config *cfg, lfs_block_t block) {
361
436
// check if erase is valid
362
437
LFS_ASSERT (block < bd -> cfg -> erase_count );
363
438
439
+ // emulate out-of-order writes? save first write
440
+ if (bd -> cfg -> powerloss_behavior == LFS_EMUBD_POWERLOSS_OOO
441
+ && bd -> ooo_block == -1 ) {
442
+ bd -> ooo_block = block ;
443
+ bd -> ooo_data = lfs_emubd_incblock (bd -> blocks [block ]);
444
+ }
445
+
364
446
// get the block
365
447
lfs_emubd_block_t * b = lfs_emubd_mutblock (cfg , & bd -> blocks [block ]);
366
448
if (!b ) {
367
- LFS_EMUBD_TRACE ("lfs_emubd_prog -> %d" , LFS_ERR_NOMEM );
449
+ LFS_EMUBD_TRACE ("lfs_emubd_erase -> %d" , LFS_ERR_NOMEM );
368
450
return LFS_ERR_NOMEM ;
369
451
}
370
452
@@ -430,8 +512,11 @@ int lfs_emubd_erase(const struct lfs_config *cfg, lfs_block_t block) {
430
512
if (bd -> power_cycles > 0 ) {
431
513
bd -> power_cycles -= 1 ;
432
514
if (bd -> power_cycles == 0 ) {
433
- // simulate power loss
434
- bd -> cfg -> powerloss_cb (bd -> cfg -> powerloss_data );
515
+ int err = lfs_emubd_powerloss (cfg );
516
+ if (err ) {
517
+ LFS_EMUBD_TRACE ("lfs_emubd_erase -> %d" , err );
518
+ return err ;
519
+ }
435
520
}
436
521
}
437
522
@@ -441,14 +526,21 @@ int lfs_emubd_erase(const struct lfs_config *cfg, lfs_block_t block) {
441
526
442
527
int lfs_emubd_sync (const struct lfs_config * cfg ) {
443
528
LFS_EMUBD_TRACE ("lfs_emubd_sync(%p)" , (void * )cfg );
529
+ lfs_emubd_t * bd = cfg -> context ;
444
530
445
- // do nothing
446
- (void )cfg ;
531
+ // emulate out-of-order writes? reset first write, writes
532
+ // cannot be out-of-order across sync
533
+ if (bd -> cfg -> powerloss_behavior == LFS_EMUBD_POWERLOSS_OOO ) {
534
+ lfs_emubd_decblock (bd -> ooo_data );
535
+ bd -> ooo_block = -1 ;
536
+ bd -> ooo_data = NULL ;
537
+ }
447
538
448
539
LFS_EMUBD_TRACE ("lfs_emubd_sync -> %d" , 0 );
449
540
return 0 ;
450
541
}
451
542
543
+
452
544
/// Additional extended API for driving test features ///
453
545
454
546
static int lfs_emubd_crc_ (const struct lfs_config * cfg ,
@@ -633,6 +725,8 @@ int lfs_emubd_copy(const struct lfs_config *cfg, lfs_emubd_t *copy) {
633
725
copy -> proged = bd -> proged ;
634
726
copy -> erased = bd -> erased ;
635
727
copy -> power_cycles = bd -> power_cycles ;
728
+ copy -> ooo_block = bd -> ooo_block ;
729
+ copy -> ooo_data = lfs_emubd_incblock (bd -> ooo_data );
636
730
copy -> disk = bd -> disk ;
637
731
if (copy -> disk ) {
638
732
copy -> disk -> rc += 1 ;
0 commit comments