8000 Added possibility to open multiple files with LFS_NO_MALLOC enabled by dpgeorge · Pull Request #58 · littlefs-project/littlefs · GitHub
[go: up one dir, main page]

Skip to content

Added possibility to open multiple files with LFS_NO_MALLOC enabled #58

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 1 commit into from
Jul 18, 2018

Conversation

dpgeorge
Copy link
Contributor
@dpgeorge dpgeorge commented Jun 8, 2018

The LFS_NO_MALLOC option is very useful, because some systems have very particular memory allocation needs. But enabled this option doesn't allow to have multiple files open at the same time. This PR adds a quick fix for this by allowing to pass in the file_buffer directly to lfs_file_open(), so the latter doesn't need to call lfs_malloc().

I don't expect this to be merged as-is because it breaks the existing API. But a feature along these lines would be very useful because it gives full functionality of littlefs without the need for any malloc() or free() functions.

Alternatives to this PR would be:

  • a new function, eg lfs_file_open_using() which accepts the 5th parameter added here
  • allow to set the global lfs->cfg->file_buffer pointer before each call to lfs_file_open() so the latter could pick up a new buffer each time

( Background: we are looking to integrate littlefs in MicroPython: micropython/micropython#3847 )

@dpgeorge dpgeorge force-pushed the file-open-no-ma 8000 lloc branch from d77ed32 to 118027b Compare June 26, 2018 01:38
@dpgeorge
Copy link
Contributor Author

I have rebased this PR on top of the latest master, with change in license.

@geky
Copy link
Member
geky commented Jun 27, 2018

Hi @dpgeorge, thanks for the pr (and rebasing). I think you're right passing a buffer into open would be a better API.

Tossing ideas around, one idea to make this future compatible would be to take in a sort of config struct. Similar to the lfs_mount/lfs_format functions:

struct lfs_file_config {
    void *buffer;
};

int lfs_file_open(lfs_t *lfs, lfs_file_t *file,
        const char *path, int flags,
        const struct lfs_file_config *cfg);

This would let us add additional configuration to the config structure in the future without breaking compatibility or having to come up with additional function names. Thoughts?

@dpgeorge
Copy link
Contributor Author

one idea to make this future compatible would be to take in a sort of config struct.

It might be simpler to just add a config entry to the lfs_file_t struct, which the user can populate if needed. Then there doesn't need to be any additional args to lfs_file_open.

Alternatively, a user could just set the existing file->cache.buffer entry manually before calling lfs_file_open, in which case the user's buffer would be used. That also doesn't require adding any args to the function.

@geky
Copy link
Member
geky commented Jun 29, 2018

It might be simpler to just add a config entry to the lfs_file_t struct, which the user can populate if needed. Then there doesn't need to be any additional args to lfs_file_open.

Hmm, although wouldn't that no longer be backwards compatible since the config entry would need to be zeroed by users that don't want to use a buffer?

8000

@dpgeorge
Copy link
Contributor Author

although wouldn't that no longer be backwards compatible since the config entry would need to be zeroed by users that don't want to use a buffer?

Yes that's true. If 100% backwards compatibility is needed there are a few options:

  1. enable the new features via a compile-time config macro
  2. provide a new function lfs_file_open_ext() that has the new behaviour
  3. provide a config function lfs_file_config() that takes the configuration struct and sets a flag in the main lfs state that it was used (this flag would be initially cleared by lfs init)

@geky
Copy link
Member
geky commented Jul 2, 2018

Those are all good ideas.

I believe the main benefit of providing a separate config struct is that it makes it clear to the user what needs to be initialized and what doesn't. And additionally the config struct could be stored in

How about we go the "lfs_file_open_ext" route and add an additional open function as lfs_file_opencfg? The simpler lfs_file_open function can still be there.


One thing I'm considering is the addition of custom attributes (#48). Introducing a config struct (or setting members of the file struct) would open up a good way to introduct custom attributes before file open:

struct my_file {
    lfs_file_t file;
    struct lfs_file_config cfg;
    struct lfs_attr attrs[2];
    uint32_t timestamp;
    uint16_t number;
};

struct my_file file;
file->attrs[0].type = MY_TYPE_TIMESTAMP;
file->attrs[0].size = sizeof(file->timestamp);
file->attrs[0].buffer = &file->timestamp;
file->attrs[1].type = MY_TYPE_NUMBER;
file->attrs[1].size = sizeof(file->number);
file->attrs[1].buffer = &file->number;
memset(&file->cfg, 0, sizeof(file->cfg));
file->cfg.attrs = &file->attrs;
file->cfg.attr_count = 2;

int err = lfs_file_opencfg(lfs, &file->file, "filename.txt", LFS_O_RDONLY, &file->cfg);

@dpgeorge
Copy link
Contributor Author
dpgeorge commented Jul 3, 2018 < 8000 /div>

How about we go the "lfs_file_open_ext" route and add an additional open function as lfs_file_opencfg? The simpler lfs_file_open function can still be there.

That sounds good.

I believe the main benefit of providing a separate config struct is that it makes it clear to the user what needs to be initialized and what doesn't.

To allow to add entries to the file config struct in a backwards-compatible way, I guess you'd require the user to always do memset(&file->cfg, 0, sizeof(file->cfg)), then populate the used entries, before calling lfs_file_opencfg().

For const file configuration structs this would still work because (in C99 at least) you can use named initialisers and the remaining entries will be zero'd out, eg:

static uint8_t my_file_buffer[128];
static const struct lfs_file_config my_file_cfg = {
    .file_buffer = my_file_buffer,
    // all other entries are 0 by default
};

One thing I'm considering is the addition of custom attributes (#48). Introducing a config struct (or setting members of the file struct) would open up a good way to introduct custom attributes before file open

Also sounds good. Although in your example above, if you open the file with LFS_O_RDONLY I assume it'll ignore the attributes in the file config, because it can't write to the file?

@geky
Copy link
Member
geky commented Jul 5, 2018

@dpgeorge How does this look to you? I added the lfs_file_opencfg onto your pr.

One other question is if these config structs should be copied into the structures during format/mount/opencfg:

  1. Copy
    • RAM only allocated for format/mount/opencfg call
    • Allows modifications by format/mount/opencfg
  2. Reference by pointer
    • Allows storing config in ROM

I went with the second option for consistency with lfs_mount.

Also sounds good. Although in your example above, if you open the file with LFS_O_RDONLY I assume it'll ignore the attributes in the file config, because it can't write to the file?

It could still read the attributes, though there wouldn't be much advantage over and explicit lfs_getattr call.

@dpgeorge
Copy link
Contributor Author
dpgeorge commented Jul 6, 2018

How does this look to you? I added the lfs_file_opencfg onto your pr.

Thanks, I see it.

One other question is if these config structs should be copied into the structures during format/mount/opencfg:
...
I went with the second option for consistency with lfs_mount.

That brings up an interesting point: for files there would be two kinds of configurations: global configuration options that are common to all files (like attributes), and local configuration options just for a file (like the cache buffer). If these are put into the same struct then it would be a waste of memory to allocate a new one of these structs for each file, since all the global config would be common and could have gone in ROM. To be explicit on this point: the void *buffer entry in lfs_file_config must be different for each file and so that requires a different instance of this struct for each file that you want open at the same time. And then you must copy into each of these structs the common global file config values, which could be quite large. Regardless of if these file config structs go in ROM or RAM it's still wasteful repeating this data.

Maybe the common, global file config (like configuration of attributes and their types) needs to go in the lft_config struct. Then only per-file config goes in lft_file_config.

@geky
Copy link
Member
geky commented Jul 6, 2018

You're right that any common configuration should go into the global struct.

But I think attributes fall into this category. A part of the attribute structure is the buffer that contain's the attribute's data. This would be unique for each file.

There's also the minor point that you may want different attributes for different files, but I'm not sure that's important.

On the plus side, you only pay the cost for the attribute structures if you use custom attributes.

@geky geky force-pushed the file-open-no-malloc branch from bf25c0b to f6e3193 Compare July 16, 2018 20:41
@geky
Copy link
Member
geky commented Jul 16, 2018

Rebased due to conflict with master and added version bump to v1.5

Hi @dpgeorge, does this change look good to you? Since it's backwards compatible I think we can go ahead and merge it without any problems (just a minor version bump).

@geky geky changed the title Added possibility to open multiple files with LFS_NO_MALLOC enabled v1.5 - Added possibility to open multiple files with LFS_NO_MALLOC enabled Jul 16, 2018
@dpgeorge
Copy link
Contributor Author

Yes it looks good to me, thanks! It does look backwards compatible.

@geky geky added the v1.5 label Jul 17, 2018
@geky geky changed the title v1.5 - Added possibility to open multiple files with LFS_NO_MALLOC enabled Added possibility to open multiple files with LFS_NO_MALLOC enabled Jul 17, 2018
@geky
Copy link
Member
geky commented Jul 17, 2018

Thanks for the initial pr!

@dpgeorge
Copy link
Contributor Author

No problem. There's not much left of my initial code/commit, I don't know if it's worth keeping it around or not.

The optional config structure options up the possibility of adding
file-level configuration in a backwards compatible manner.

Also adds possibility to open multiple files with LFS_NO_MALLOC
enabled thanks to dpgeorge

Also bumped minor version to v1.5
@geky geky force-pushed the file-open-no-malloc branch from f6e3193 to 961fab7 Compare July 17, 2018 23:33
@geky
8000 Copy link
Member
geky commented Jul 17, 2018

Sure thing, squashed, should be good to go once CI is done

@dpgeorge
Copy link
Contributor Author

Ok, I'm happy with it.

@geky geky merged commit 16318d0 into littlefs-project:master Jul 18, 2018
@dpgeorge dpgeorge deleted the file-open-no-malloc branch July 18, 2018 01:54
@dpgeorge
Copy link
Contributor Author

Thanks for the work to get this merged, it's much appreciated! FYI here is the change I made to support this new lfs_file_opencfg() function: micropython/micropython@4b6bbbd

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

Successfully merging this pull request may close these issues.

2 participants
0