Skip to content

littlefs: Fix some issues with lookahead trust #6604

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 19, 2018

Conversation

geky
Copy link
Contributor

@geky geky commented Apr 11, 2018

Description

Two somewhat related issues were found over here: littlefs-project/littlefs#46

After quite a bit of discussion the result is some fixes a bit of simplification of the lookahead management. Most significantly, removing the dependency on integer overflow. This should hopefully remove a lot of the issues we've been seeing around allocation.

  1. Fix issue with lookahead trusting old lookahead blocks

    One of the big simplifications in littlefs's implementation is the complete lack of tracking free blocks, allowing operations to simply drop blocks that are no longer in use.

    However, this means the lookahead buffer can easily contain outdated blocks that were previously deleted. This is usually fine, as littlefs will rescan the storage if it can't find a free block in the lookahead
    buffer, but after changes that caused littlefs to more conservatively respect the alloc acks (e611cf5), any scanned blocks after an ack would be incorrectly trusted.

    The fix is to eagerly scan ahead in the lookahead when we allocate so that alloc acks are better able to discredit old lookahead blocks. Since usually alloc acks are tightly coupled to allocations of one or two blocks, this allows littlefs to properly rescan every set of allocations.

    This may still be a concern if there is a long series of worn out blocks, but in the worst case littlefs will conservatively avoid using blocks it's not sure about.

  2. Fixed lookahead overflow and removed unbounded lookahead pointers

    The lookahead pointer modular arithmetic does not work around integer overflow when the pointer size is not a multiple of the block count.

    To avoid overflow problems, the easy solution is to stop trying to work around integer overflows and keep the lookahead offset inside the block device. To make this work, the ack was modified into a resetable counter that is decremented every block allocation.

    As a plus, quite a bit of the allocation logic ended up simplified.

Pull request type

[✓] Fix
[ ] Refactor
[ ] New target
[ ] Feature
[ ] Breaking change

One of the big simplifications in littlefs's implementation is the
complete lack of tracking free blocks, allowing operations to simply
drop blocks that are no longer in use.

However, this means the lookahead buffer can easily contain outdated
blocks that were previously deleted. This is usually fine, as littlefs
will rescan the storage if it can't find a free block in the lookahead
buffer, but after changes that caused littlefs to more conservatively
respect the alloc acks (e611cf5), any scanned blocks after an ack would
be incorrectly trusted.

The fix is to eagerly scan ahead in the lookahead when we allocate so
that alloc acks are better able to discredit old lookahead blocks. Since
usually alloc acks are tightly coupled to allocations of one or two blocks,
this allows littlefs to properly rescan every set of allocations.

This may still be a concern if there is a long series of worn out
blocks, but in the worst case littlefs will conservatively avoid using
blocks it's not sure about.

Found by davidefer
…inters

As pointed out by davidefer, the lookahead pointer modular arithmetic
does not work around integer overflow when the pointer size is not a
multiple of the block count.

To avoid overflow problems, the easy solution is to stop trying to
work around integer overflows and keep the lookahead offset inside the
block device. To make this work, the ack was modified into a resetable
counter that is decremented every block allocation.

As a plus, quite a bit of the allocation logic ended up simplified.
@@ -301,5 +301,128 @@ tests/test.py << TEST
lfs_unmount(&lfs) => 0;
TEST

echo "--- Outdated lookahead test ---"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this mean in regards to outdated?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test is putting littlefs into the state where the lookahead buffer is filled with files that have been deleted. Making the state of the lookahead buffer outdated.

This happens when you delete files after populating the lookahead buffer.

It's up to the filesystem to recognize this situation and correctly refill the lookahead buffer.

Does that make sense?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotchya! Yeah that makes sense.

kegilbert
kegilbert previously approved these changes Apr 12, 2018
Copy link
Contributor

@kegilbert kegilbert left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

lfs_block_t off;
lfs_block_t size;
lfs_block_t i;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we have better name for i? Other variables pretty much explain the purpose, except i.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any suggestions? : )

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lfs->free.off_off?

Copy link
Contributor

@0xc0170 0xc0170 Apr 13, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anything but i .
My guess without looking at what it does - just a counter so a user does not need to initialize another variable for (int i = 0...) 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, that's exactly what it is... a counter, it's state just lasts outside of a function

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then name it counter_for_something (replace somthing what it counts, what value it holds)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Counter / index ?

Copy link
Contributor Author

@geky geky Apr 13, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nah, I like counter_for_what_it_counts

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I joke, sure I can change it to index once I'm somewhere I can push to github

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is updated

Copy link

@deepikabhavnani deepikabhavnani left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good.. 👍

@0xc0170
Copy link
Contributor

0xc0170 commented Apr 16, 2018

/morph build

@mbed-ci
Copy link

mbed-ci commented Apr 16, 2018

Build : SUCCESS

Build number : 1752
Build artifacts/logs : http://mbed-os.s3-website-eu-west-1.amazonaws.com/?prefix=builds/6604/

Triggering tests

/morph test
/morph uvisor-test
/morph export-build
/morph mbed2-build

@mbed-ci
Copy link

mbed-ci commented Apr 16, 2018

@mbed-ci
Copy link

mbed-ci commented Apr 16, 2018

@geky
Copy link
Contributor Author

geky commented Apr 16, 2018

So what is pr-head up to?

@0xc0170
Copy link
Contributor

0xc0170 commented Apr 16, 2018

So what is pr-head up to?

CI team is looking at it currently how to fix it in jenkins and also Github support also looking at the breakage

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants