# Test checksum validation things after = ['test_traversal', 'test_gc', 'test_mount'] # Test filesystem-level checksum things # test we can detect at least fully clobbered blocks [cases.test_ck_ckmeta_easy] # METHOD=0 => lfsr_fs_ckmeta # METHOD=1 => lfsr_fs_gc # METHOD=2 => lfsr_traversal_read # METHOD=3 => lfsr_mount defines.METHOD = [0, 1, 2, 3] defines.N = [1, 2, 4, 8, 16, 32, 64] defines.SIZE = [ '0', 'FILE_BUFFER_SIZE/2', '2*FILE_BUFFER_SIZE', 'BLOCK_SIZE/2', 'BLOCK_SIZE', '2*BLOCK_SIZE', '8*BLOCK_SIZE', ] if = '(SIZE*N)/BLOCK_SIZE <= 32' code = ''' lfs_block_t i = 0; while (true) { // a bit hacky, but this catches infinite loops assert(i < 2*BLOCK_COUNT); lfs_t lfs; lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; // create an interesting filesystem uint32_t prng = 42; for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "squid%03x", i); uint8_t wbuf[SIZE]; for (lfs_size_t j = 0; j < SIZE; j++) { wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26); } lfsr_file_t file; lfsr_file_open(&lfs, &file, name, LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; lfsr_file_write(&lfs, &file, wbuf, SIZE) => SIZE; lfsr_file_close(&lfs, &file) => 0; } // traverse to find blocks lfsr_traversal_t t; lfsr_traversal_open(&lfs, &t, 0) => 0; lfs_block_t k = 0; for (lfs_block_t j = 0;; j++) { assert(j < 2*BLOCK_COUNT); struct lfs_tinfo tinfo; int err = lfsr_traversal_read(&lfs, &t, &tinfo); assert(!err || err == LFS_ERR_NOENT); if (err == LFS_ERR_NOENT) { lfsr_traversal_close(&lfs, &t) => 0; lfsr_unmount(&lfs) => 0; goto done; } // this gets a bit tricky be cause we need to clobber both // blocks in mdir pairs if (tinfo.btype == LFS_BTYPE_MDIR || tinfo.btype == LFS_BTYPE_BTREE) { if (k == i || k == i+1) { // clobber this block printf("clobbering 0x%x\n", tinfo.block); uint8_t clobber_buf[BLOCK_SIZE]; memset(clobber_buf, 0xcc, BLOCK_SIZE); CFG->erase(CFG, tinfo.block) => 0; CFG->prog(CFG, tinfo.block, 0, clobber_buf, BLOCK_SIZE) => 0; if (tinfo.btype != LFS_BTYPE_MDIR || k == i+1) { i += (tinfo.btype == LFS_BTYPE_MDIR) ? 2 : 1; lfsr_traversal_close(&lfs, &t) => 0; goto clobbered; } } k += 1; } } clobbered:; // find clobbered blocks with lfsr_fs_ckmeta if (METHOD == 0) { lfsr_fs_ckmeta(&lfs) => LFS_ERR_CORRUPT; // find clobbered blocks with lfsr_fs_gc } else if (METHOD == 1) { lfsr_fs_gc(&lfs, -1, LFS_GC_CKMETA) => LFS_ERR_CORRUPT; // find clobbered blocks with lfsr_traversal_read } else if (METHOD == 2) { lfsr_traversal_t t; lfsr_traversal_open(&lfs, &t, LFS_T_CKMETA) => 0; for (lfs_block_t i = 0;; i++) { // a bit hacky, but this catches infinite loops LFS_ASSERT(i < 2*BLOCK_COUNT); struct lfs_tinfo tinfo; int err = lfsr_traversal_read(&lfs, &t, &tinfo); assert(!err || err == LFS_ERR_CORRUPT); if (err == LFS_ERR_CORRUPT) { break; } } lfsr_traversal_close(&lfs, &t) => 0; // find clobbered blocks with lfsr_mount } else if (METHOD == 3) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, LFS_M_RDWR | LFS_M_CKMETA, CFG) => LFS_ERR_CORRUPT; } else { assert(false); } if (METHOD != 3) { lfsr_unmount(&lfs) => 0; } } done:; ''' [cases.test_ck_ckdata_easy] # METHOD=0 => lfsr_fs_ckdata # METHOD=1 => lfsr_fs_gc # METHOD=2 => lfsr_traversal_read # METHOD=3 => lfsr_mount defines.METHOD = [0, 1, 2, 3] defines.N = [1, 2, 4, 8, 16, 32, 64] defines.SIZE = [ '0', 'FILE_BUFFER_SIZE/2', '2*FILE_BUFFER_SIZE', 'BLOCK_SIZE/2', 'BLOCK_SIZE', '2*BLOCK_SIZE', '8*BLOCK_SIZE', ] if = '(SIZE*N)/BLOCK_SIZE <= 32' code = ''' lfs_block_t i = 0; while (true) { // a bit hacky, but this catches infinite loops assert(i < 2*BLOCK_COUNT); lfs_t lfs; lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; // create an interesting filesystem uint32_t prng = 42; for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "squid%03x", i); uint8_t wbuf[SIZE]; for (lfs_size_t j = 0; j < SIZE; j++) { wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26); } lfsr_file_t file; lfsr_file_open(&lfs, &file, name, LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; lfsr_file_write(&lfs, &file, wbuf, SIZE) => SIZE; lfsr_file_close(&lfs, &file) => 0; } // traverse to find blocks lfsr_traversal_t t; lfsr_traversal_open(&lfs, &t, 0) => 0; lfs_block_t k = 0; for (lfs_block_t j = 0;; j++) { assert(j < 2*BLOCK_COUNT); struct lfs_tinfo tinfo; int err = lfsr_traversal_read(&lfs, &t, &tinfo); assert(!err || err == LFS_ERR_NOENT); if (err == LFS_ERR_NOENT) { lfsr_traversal_close(&lfs, &t) => 0; lfsr_unmount(&lfs) => 0; goto done; } // this gets a bit tricky be cause we need to clobber both // blocks in mdir pairs if (tinfo.btype == LFS_BTYPE_MDIR || tinfo.btype == LFS_BTYPE_BTREE || tinfo.btype == LFS_BTYPE_DATA) { if (k == i || k == i+1) { // clobber this block printf("clobbering 0x%x\n", tinfo.block); uint8_t clobber_buf[BLOCK_SIZE]; memset(clobber_buf, 0xcc, BLOCK_SIZE); CFG->erase(CFG, tinfo.block) => 0; CFG->prog(CFG, tinfo.block, 0, clobber_buf, BLOCK_SIZE) => 0; if (tinfo.btype != LFS_BTYPE_MDIR || k == i+1) { i += (tinfo.btype == LFS_BTYPE_MDIR) ? 2 : 1; lfsr_traversal_close(&lfs, &t) => 0; goto clobbered; } } k += 1; } } clobbered:; // find clobbered blocks with lfsr_fs_ckmeta if (METHOD == 0) { lfsr_fs_ckdata(&lfs) => LFS_ERR_CORRUPT; // find clobbered blocks with lfsr_fs_gc } else if (METHOD == 1) { lfsr_fs_gc(&lfs, -1, LFS_GC_CKDATA) => LFS_ERR_CORRUPT; // find clobbered blocks with lfsr_traversal_read } else if (METHOD == 2) { lfsr_traversal_t t; lfsr_traversal_open(&lfs, &t, LFS_T_CKDATA) => 0; for (lfs_block_t i = 0;; i++) { // a bit hacky, but this catches infinite loops LFS_ASSERT(i < 2*BLOCK_COUNT); struct lfs_tinfo tinfo; int err = lfsr_traversal_read(&lfs, &t, &tinfo); assert(!err || err == LFS_ERR_CORRUPT); if (err == LFS_ERR_CORRUPT) { break; } } lfsr_traversal_close(&lfs, &t) => 0; // find clobbered blocks with lfsr_mount } else if (METHOD == 3) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, LFS_M_RDWR | LFS_M_CKDATA, CFG) => LFS_ERR_CORRUPT; } else { assert(false); } if (METHOD != 3) { lfsr_unmount(&lfs) => 0; } } done:; ''' # Test file-level checksum things # test we can detect at least fully clobbered blocks [cases.test_ck_file_ckmeta_easy] # METHOD=0 => lfsr_file_ckmeta # METHOD=1 => lfsr_file_close+open+ckmeta defines.METHOD = [0, 1] defines.N = [1, 2, 4, 8, 16, 32, 64] defines.SIZE = [ '0', 'FILE_BUFFER_SIZE/2', '2*FILE_BUFFER_SIZE', 'BLOCK_SIZE/2', 'BLOCK_SIZE', '2*BLOCK_SIZE', '8*BLOCK_SIZE', ] code = ''' for (lfs_block_t i = 0;; i++) { // a bit hacky, but this catches infinite loops assert(i < 2*BLOCK_COUNT); lfs_t lfs; lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; // create an interesting file uint32_t prng = 42; lfsr_file_t file; lfsr_file_open(&lfs, &file, "octopus", LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0; uint8_t wbuf[SIZE]; for (lfs_size_t j = 0; j < SIZE; j++) { wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26); } lfsr_file_write(&lfs, &file, wbuf, SIZE) => SIZE; // traverse to find blocks lfsr_traversal_t t; lfsr_traversal_open(&lfs, &t, 0) => 0; lfs_block_t k = 0; for (lfs_block_t j = 0;; j++) { assert(j < 2*BLOCK_COUNT); struct lfs_tinfo tinfo; int err = lfsr_traversal_read(&lfs, &t, &tinfo); assert(!err || err == LFS_ERR_NOENT); if (err == LFS_ERR_NOENT) { lfsr_traversal_close(&lfs, &t) => 0; lfsr_file_close(&lfs, &file) => 0; lfsr_unmount(&lfs) => 0; goto done; } if (tinfo.btype == LFS_BTYPE_BTREE) { if (k == i) { // clobber this block printf("clobbering 0x%x\n", tinfo.block); uint8_t clobber_buf[BLOCK_SIZE]; memset(clobber_buf, 0xcc, BLOCK_SIZE); CFG->erase(CFG, tinfo.block) => 0; CFG->prog(CFG, tinfo.block, 0, clobber_buf, BLOCK_SIZE) => 0; lfsr_traversal_close(&lfs, &t) => 0; goto clobbered; } k += 1; } } clobbered:; // find clobbered blocks with lfsr_file_ckmeta if (METHOD == 0) { lfsr_file_ckmeta(&lfs, &file) => LFS_ERR_CORRUPT; // find clobbered blocks with lfsr_file_close+open+ckmeta } else if (METHOD == 1) { lfsr_file_close(&lfs, &file) => 0; lfsr_file_open(&lfs, &file, "octopus", LFS_O_RDONLY) => 0; lfsr_file_ckmeta(&lfs, &file) => LFS_ERR_CORRUPT; } else { assert(false); } lfsr_file_close(&lfs, &file) => 0; lfsr_unmount(&lfs) => 0; } done:; ''' # test we can detect at least fully clobbered blocks [cases.test_ck_file_ckdata_easy] # METHOD=0 => lfsr_file_ckdata # METHOD=1 => lfsr_file_close+open+ckdata defines.METHOD = [0, 1] defines.N = [1, 2, 4, 8, 16, 32, 64] defines.SIZE = [ '0', 'FILE_BUFFER_SIZE/2', '2*FILE_BUFFER_SIZE', 'BLOCK_SIZE/2', 'BLOCK_SIZE', '2*BLOCK_SIZE', '8*BLOCK_SIZE', ] code = ''' for (lfs_block_t i = 0;; i++) { // a bit hacky, but this catches infinite loops assert(i < 2*BLOCK_COUNT); lfs_t lfs; lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; // create an interesting file uint32_t prng = 42; lfsr_file_t file; lfsr_file_open(&lfs, &file, "octopus", LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0; uint8_t wbuf[SIZE]; for (lfs_size_t j = 0; j < SIZE; j++) { wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26); } lfsr_file_write(&lfs, &file, wbuf, SIZE) => SIZE; // traverse to find blocks lfsr_traversal_t t; lfsr_traversal_open(&lfs, &t, 0) => 0; lfs_block_t k = 0; for (lfs_block_t j = 0;; j++) { assert(j < 2*BLOCK_COUNT); struct lfs_tinfo tinfo; int err = lfsr_traversal_read(&lfs, &t, &tinfo); assert(!err || err == LFS_ERR_NOENT); if (err == LFS_ERR_NOENT) { lfsr_traversal_close(&lfs, &t) => 0; lfsr_file_close(&lfs, &file) => 0; lfsr_unmount(&lfs) => 0; goto done; } if (tinfo.btype == LFS_BTYPE_BTREE || tinfo.btype == LFS_BTYPE_DATA) { if (k == i) { // clobber this block printf("clobbering 0x%x\n", tinfo.block); uint8_t clobber_buf[BLOCK_SIZE]; memset(clobber_buf, 0xcc, BLOCK_SIZE); CFG->erase(CFG, tinfo.block) => 0; CFG->prog(CFG, tinfo.block, 0, clobber_buf, BLOCK_SIZE) => 0; lfsr_traversal_close(&lfs, &t) => 0; goto clobbered; } k += 1; } } clobbered:; // find clobbered blocks with lfsr_file_ckmeta if (METHOD == 0) { lfsr_file_ckdata(&lfs, &file) => LFS_ERR_CORRUPT; // find clobbered blocks with lfsr_file_close+open+ckmeta } else if (METHOD == 1) { lfsr_file_close(&lfs, &file) => 0; lfsr_file_open(&lfs, &file, "octopus", LFS_O_RDONLY) => 0; lfsr_file_ckdata(&lfs, &file) => LFS_ERR_CORRUPT; } else { assert(false); } lfsr_file_close(&lfs, &file) => 0; lfsr_unmount(&lfs) => 0; } done:; '''