)]}'
{
  "commit": "0aba71d0d6d57813db2306670a9dd9d25efdfae5",
  "tree": "7003eda1c3248b90dfd980d9ed83d3556597ee5a",
  "parents": [
    "0ea2871e2472c779e686f0af76e45927cb20b72d"
  ],
  "author": {
    "name": "Christopher Haster",
    "email": "chaster@utexas.edu",
    "time": "Sun Nov 22 15:07:16 2020 -0600"
  },
  "committer": {
    "name": "Christopher Haster",
    "email": "chaster@utexas.edu",
    "time": "Sun Nov 22 15:07:16 2020 -0600"
  },
  "message": "Fixed single unchecked bit during commit verification\n\nThis bug was exposed by the bad-block tests due to changes to block\nallocation, but could have been hit before these changes.\n\nIn flash, when blocks fail, they don\u0027t fail in a predictable manner. To\naccount for this, the bad-block tests check a number of failure\nbehaviors. The interesting one here is \"LFS_TESTBD_BADBLOCK_ERASENOOP\",\nin which bad blocks can not be erased or programmed, and are stuck with\nthe data written at the time the blocks go bad.\n\nThis is actually a pretty realistic failure behavior, since flash needs a\nlarge voltage to force the electrons of the floating gates. Though\nrealistically, such a failure would like corrupt the data a bit, not leave the\nunderlying data perfectly intact.\n\nLFS_TESTBD_BADBLOCK_ERASENOOP is rather interesting to test for because it\nmeans bad blocks can end up with perfectly valid CRCs after a failed write,\nconfusing littlefs.\n\n---\n\nIn this case, we had the perfect series of operations such that a test\nwas repeatedly writing the same sequence of metadata commits to the same\nblock, which eventually goes bad, leaving the block stuck with metadata\nthat occurs later in the sequence.\n\nWhat this means is that after the first commit, the metadata block\ncontained both the first and second commits, even though the loop in the\ntest hadn\u0027t reached that point yet.\n\nexpected       actual\n.----------.  .----------.\n| commit 1 |  | commit 1 |\n| crc 1    |  | crc 1    |\n|          |  | commit 2 \u003c-- (from previous iteration)\n|          |  | crc 2    |\n\u0027----------\u0027  \u0027----------\u0027\n\nTo protect against this, littlefs normally compares the written CRC\nagainst the expected CRC, but because this was the exact same data that\nit was going to write, this CRCs end up the same.\n\nAh! But doesn\u0027t littlefs also encode the state of the next page to keep\ntrack of if the next page has been erased or not? Wouldn\u0027t that change\nbetween iterations?\n\nIt does! In a single bit in the CRC-tag. But thanks to some incorrect\nlogic attempting to avoid an extra condition in the loop for writing out\npadding commits, the CRC that littlefs checked against was the CRC\nimmediately before we include the \"is-next-page-erased\" bit.\n\nChanging the verification check to use the same CRC as what is used to\nverify commits on fetch solves this problem.\n",
  "tree_diff": [
    {
      "type": "modify",
      "old_id": "45210640ad445aad2a8d44fd94cde0f3522a18d7",
      "old_mode": 33188,
      "old_path": "lfs.c",
      "new_id": "019db1f001ab8712666e17228092952ecee0c552",
      "new_mode": 33188,
      "new_path": "lfs.c"
    }
  ]
}
