예제 #1
0
void dump_erase_counts(spiffs *fs) {
  spiffs_block_ix bix;
  printf("  BLOCK     |\n");
  printf("   AGE COUNT|\n");
  for (bix = 0; bix < fs->block_count; bix++) {
    printf("----%3i ----|", bix);
  }
  printf("\n");
  for (bix = 0; bix < fs->block_count; bix++) {
    spiffs_obj_id erase_mark;
    _spiffs_rd(fs, 0, 0, SPIFFS_ERASE_COUNT_PADDR(fs, bix), sizeof(spiffs_obj_id), (uint8_t *)&erase_mark);
    if (erases[bix] == 0) {
      printf("            |");
    } else {
      printf("%7i %4i|", (fs->max_erase_count - erase_mark), erases[bix]);
    }
  }
  printf("\n");
}
예제 #2
0
// Finds block candidates to erase
s32_t spiffs_gc_find_candidate(
    spiffs *fs,
    spiffs_block_ix **block_candidates,
    int *candidate_count,
    char fs_crammed) {
  s32_t res = SPIFFS_OK;
  u32_t blocks = fs->block_count;
  spiffs_block_ix cur_block = 0;
  u32_t cur_block_addr = 0;
  spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;
  int cur_entry = 0;

  // using fs->work area as sorted candidate memory, (spiffs_block_ix)cand_bix/(s32_t)score
  int max_candidates = MIN(fs->block_count, (SPIFFS_CFG_LOG_PAGE_SZ(fs)-8)/(sizeof(spiffs_block_ix) + sizeof(s32_t)));
  *candidate_count = 0;
  c_memset(fs->work, 0xff, SPIFFS_CFG_LOG_PAGE_SZ(fs));

  // divide up work area into block indices and scores
  // todo alignment?
  spiffs_block_ix *cand_blocks = (spiffs_block_ix *)fs->work;
  s32_t *cand_scores = (s32_t *)(fs->work + max_candidates * sizeof(spiffs_block_ix));

  *block_candidates = cand_blocks;

  int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));

  // check each block
  while (res == SPIFFS_OK && blocks--) {
    u16_t deleted_pages_in_block = 0;
    u16_t used_pages_in_block = 0;

    int obj_lookup_page = 0;
    // check each object lookup page
    while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
      int entry_offset = obj_lookup_page * entries_per_page;
      res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
          0, cur_block_addr + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
      // check each entry
      while (res == SPIFFS_OK &&
          cur_entry - entry_offset < entries_per_page &&
          cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) {
        spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];
        if (obj_id == SPIFFS_OBJ_ID_FREE) {
          // when a free entry is encountered, scan logic ensures that all following entries are free also
          res = 1; // kill object lu loop
          break;
        } else  if (obj_id == SPIFFS_OBJ_ID_DELETED) {
          deleted_pages_in_block++;
        } else {
          used_pages_in_block++;
        }
        cur_entry++;
      } // per entry
      obj_lookup_page++;
    } // per object lookup page
    if (res == 1) res = SPIFFS_OK;

    // calculate score and insert into candidate table
    // stoneage sort, but probably not so many blocks
    if (res == SPIFFS_OK && deleted_pages_in_block > 0) {
      // read erase count
      spiffs_obj_id erase_count;
      res = _spiffs_rd(fs, SPIFFS_OP_C_READ | SPIFFS_OP_T_OBJ_LU2, 0,
          SPIFFS_ERASE_COUNT_PADDR(fs, cur_block),
          sizeof(spiffs_obj_id), (u8_t *)&erase_count);
      SPIFFS_CHECK_RES(res);

      spiffs_obj_id erase_age;
      if (fs->max_erase_count > erase_count) {
        erase_age = fs->max_erase_count - erase_count;
      } else {
        erase_age = SPIFFS_OBJ_ID_FREE - (erase_count - fs->max_erase_count);
      }

      s32_t score =
          deleted_pages_in_block * SPIFFS_GC_HEUR_W_DELET +
          used_pages_in_block * SPIFFS_GC_HEUR_W_USED +
          erase_age * (fs_crammed ? 0 : SPIFFS_GC_HEUR_W_ERASE_AGE);
      int cand_ix = 0;
      SPIFFS_GC_DBG("gc_check: bix:%i del:%i use:%i score:%i\n", cur_block, deleted_pages_in_block, used_pages_in_block, score);
      while (cand_ix < max_candidates) {
        if (cand_blocks[cand_ix] == (spiffs_block_ix)-1) {
          cand_blocks[cand_ix] = cur_block;
          cand_scores[cand_ix] = score;
          break;
        } else if (cand_scores[cand_ix] < score) {
          int reorder_cand_ix = max_candidates - 2;
          while (reorder_cand_ix >= cand_ix) {
            cand_blocks[reorder_cand_ix + 1] = cand_blocks[reorder_cand_ix];
            cand_scores[reorder_cand_ix + 1] = cand_scores[reorder_cand_ix];
            reorder_cand_ix--;
          }
          cand_blocks[cand_ix] = cur_block;
          cand_scores[cand_ix] = score;
          break;
        }
        cand_ix++;
      }
      (*candidate_count)++;
    }

    cur_entry = 0;
    cur_block++;
    cur_block_addr += SPIFFS_CFG_LOG_BLOCK_SZ(fs);
  } // per block

  return res;
}
예제 #3
0
s32_t SPIFFS_vis(spiffs *fs) {
  s32_t res = SPIFFS_OK;
  SPIFFS_API_CHECK_MOUNT(fs);
  SPIFFS_LOCK(fs);

  int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));
  spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;
  spiffs_block_ix bix = 0;

  while (bix < fs->block_count) {
    // check each object lookup page
    int obj_lookup_page = 0;
    int cur_entry = 0;

    while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
      int entry_offset = obj_lookup_page * entries_per_page;
      res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
          0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
      // check each entry
      while (res == SPIFFS_OK &&
          cur_entry - entry_offset < entries_per_page && cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) {
        spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];
        if (cur_entry == 0) {
          spiffs_printf("%4i ", bix);
        } else if ((cur_entry & 0x3f) == 0) {
          spiffs_printf("     ");
        }
        if (obj_id == SPIFFS_OBJ_ID_FREE) {
          spiffs_printf(SPIFFS_TEST_VIS_FREE_STR);
        } else if (obj_id == SPIFFS_OBJ_ID_DELETED) {
          spiffs_printf(SPIFFS_TEST_VIS_DELE_STR);
        } else if (obj_id & SPIFFS_OBJ_ID_IX_FLAG){
          spiffs_printf(SPIFFS_TEST_VIS_INDX_STR(obj_id));
        } else {
          spiffs_printf(SPIFFS_TEST_VIS_DATA_STR(obj_id));
        }
        cur_entry++;
        if ((cur_entry & 0x3f) == 0) {
          spiffs_printf("\n");
        }
      } // per entry
      obj_lookup_page++;
    } // per object lookup page

    spiffs_obj_id erase_count;
    res = _spiffs_rd(fs, SPIFFS_OP_C_READ | SPIFFS_OP_T_OBJ_LU2, 0,
        SPIFFS_ERASE_COUNT_PADDR(fs, bix),
        sizeof(spiffs_obj_id), (u8_t *)&erase_count);
    SPIFFS_CHECK_RES(res);

    if (erase_count != (spiffs_obj_id)-1) {
      spiffs_printf("\tera_cnt: %d\n", erase_count);
    } else {
      spiffs_printf("\tera_cnt: N/A\n");
    }

    bix++;
  } // per block

  spiffs_printf("era_cnt_max: %d\n", fs->max_erase_count);
  spiffs_printf("last_errno:  %d\n", fs->errno);
  spiffs_printf("blocks:      %d\n", fs->block_count);
  spiffs_printf("free_blocks: %d\n", fs->free_blocks);
  spiffs_printf("page_alloc:  %d\n", fs->stats_p_allocated);
  spiffs_printf("page_delet:  %d\n", fs->stats_p_deleted);

  SPIFFS_UNLOCK(fs);
  return res;
}