Added support for custom attributes leveraging the new metadata logging

Now that littlefs has been rebuilt almost from the ground up with the
intention to support custom attributes, adding in custom attribute
support is relatively easy.

The highest bit in the 9-bit type structure indicates that an attribute
is a user-specified custom attribute. The user then has a full 8-bits to
specify the attribute type. Other than that, custom attributes are
treated the same as system-level attributes.

Also made some tweaks to custom attributes:
- Adopted the opencfg for file-level attributes provided by dpgeorge
- Changed setattrs/getattrs to the simpler setattr/getattr functions
  users will probably be more familiar with. Note that multiple
  attributes can still be committed atomically with files, though not
  with directories.
- Changed LFS_ATTRS_MAX -> LFS_ATTR_MAX since there's no longer a global
  limit on the sum of attribute sizes, which was rather confusing.
  Though they are still limited by what can fit in a metadata-pair.
This commit is contained in:
Christopher Haster
2018-07-29 15:03:23 -05:00
parent 3914cdf39f
commit 15d156082c
4 changed files with 337 additions and 227 deletions
+62 -51
View File
@@ -52,18 +52,18 @@ typedef uint32_t lfs_block_t;
// Maximum inline file size in bytes. Large inline files require a larger
// read and prog cache, but if a file can be inline it does not need its own
// data block. LFS_ATTRS_MAX + LFS_INLINE_MAX must be <= 0xffff. Stored in
// data block. LFS_ATTR_MAX + LFS_INLINE_MAX must be <= 0xffff. Stored in
// superblock and must be respected by other littlefs drivers.
#ifndef LFS_INLINE_MAX
#define LFS_INLINE_MAX 0x3ff
#endif
// Maximum size of all attributes per file in bytes, may be redefined but a
// a smaller LFS_ATTRS_MAX has no benefit. LFS_ATTRS_MAX + LFS_INLINE_MAX
// a smaller LFS_ATTR_MAX has no benefit. LFS_ATTR_MAX + LFS_INLINE_MAX
// must be <= 0xffff. Stored in superblock and must be respected by other
// littlefs drivers.
#ifndef LFS_ATTRS_MAX
#define LFS_ATTRS_MAX 0x3f
#ifndef LFS_ATTR_MAX
#define LFS_ATTR_MAX 0x3f
#endif
// Max name size in bytes, may be redefined to reduce the size of the
@@ -89,8 +89,7 @@ enum lfs_error {
LFS_ERR_NOSPC = -28, // No space left on device
LFS_ERR_NOMEM = -12, // No more memory available
LFS_ERR_NAMETOOLONG = -36, // File name too long
LFS_ERR_NODATA = -61, // No data/attr available
LFS_ERR_RANGE = -34, // Result not representable
LFS_ERR_NOATTR = -61, // No data/attr available
};
// File types
@@ -119,6 +118,7 @@ enum lfs_type {
LFS_FROM_REGION = 0x000,
LFS_FROM_DISK = 0x200,
LFS_FROM_MOVE = 0x030,
LFS_FROM_ATTRS = 0x020,
};
// File open flags
@@ -223,10 +223,10 @@ struct lfs_config {
lfs_size_t inline_size;
// Optional upper limit on attributes per file in bytes. No downside for
// larger attributes size but must be less than LFS_ATTRS_MAX. Defaults to
// LFS_ATTRS_MAX when zero.Stored in superblock and must be respected by
// larger attributes size but must be less than LFS_ATTR_MAX. Defaults to
// LFS_ATTR_MAX when zero.Stored in superblock and must be respected by
// other littlefs drivers.
lfs_size_t attrs_size;
lfs_size_t attr_size;
// Optional upper limit on length of file names in bytes. No downside for
// larger names except the size of the info struct which is controlled by
@@ -235,7 +235,6 @@ struct lfs_config {
lfs_size_t name_size;
};
// File info structure
struct lfs_info {
// Type of the file, either LFS_TYPE_REG or LFS_TYPE_DIR
@@ -256,16 +255,30 @@ struct lfs_attr {
// Pointer to buffer containing the attribute
void *buffer;
// Size of attribute in bytes, limited to LFS_ATTRS_MAX
// Size of attribute in bytes, limited to LFS_ATTR_MAX
lfs_size_t size;
// Pointer to next attribute in linked list
const struct lfs_attr *next;
};
// Optional configuration provided during lfs_file_opencfg
struct lfs_file_config {
// Optional, statically allocated buffer for files. Must be program sized.
// If NULL, malloc will be used by default.
void *buffer;
// Optional, custom attributes
// TODO document more
const struct lfs_attr *attrs;
};
/// littlefs data structures ///
typedef struct lfs_mattr {
const struct lfs_mattr *next;
int32_t tag;
const void *buffer;
const struct lfs_mattr *next;
} lfs_mattr_t;
typedef struct lfs_globals {
@@ -302,13 +315,13 @@ typedef struct lfs_file {
lfs_size_t size;
} ctz;
const struct lfs_file_config *cfg;
const struct lfs_attr *attrs;
uint32_t flags;
lfs_off_t pos;
lfs_block_t block;
lfs_off_t off;
lfs_cache_t cache;
lfs_mattr_t *attrs;
} lfs_file_t;
typedef struct lfs_dir {
@@ -328,7 +341,7 @@ typedef struct lfs_superblock {
lfs_size_t block_count;
lfs_size_t inline_size;
lfs_size_t attrs_size;
lfs_size_t attr_size;
lfs_size_t name_size;
} lfs_superblock_t;
@@ -358,7 +371,7 @@ typedef struct lfs {
lfs_globals_t diff;
lfs_size_t inline_size;
lfs_size_t attrs_size;
lfs_size_t attr_size;
lfs_size_t name_size;
} lfs_t;
@@ -368,7 +381,8 @@ typedef struct lfs {
// Format a block device with the littlefs
//
// Requires a littlefs object and config struct. This clobbers the littlefs
// object, and does not leave the filesystem mounted.
// object, and does not leave the filesystem mounted. The config struct must
// be zeroed for defaults and backwards compatibility.
//
// Returns a negative error code on failure.
int lfs_format(lfs_t *lfs, const struct lfs_config *config);
@@ -377,7 +391,8 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *config);
//
// Requires a littlefs object and config struct. Multiple filesystems
// may be mounted simultaneously with multiple littlefs objects. Both
// lfs and config must be allocated while mounted.
// lfs and config must be allocated while mounted. The config struct must
// be zeroed for defaults and backwards compatibility.
//
// Returns a negative error code on failure.
int lfs_mount(lfs_t *lfs, const struct lfs_config *config);
@@ -416,9 +431,10 @@ int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info);
// smaller than the buffer, it is padded with zeros. It the stored attribute
// is larger than the buffer, LFS_ERR_RANGE is returned.
//
// TODO doc
// Returns a negative error code on failure.
int lfs_getattrs(lfs_t *lfs, const char *path,
const struct lfs_attr *attrs, int count);
lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path,
uint8_t type, void *buffer, lfs_size_t size);
// Set custom attributes
//
@@ -426,23 +442,38 @@ int lfs_getattrs(lfs_t *lfs, const char *path,
// disk based on their type id. Unspecified attributes are left unmodified.
// Specifying an attribute with zero size deletes the attribute.
//
// TODO doc
// Returns a negative error code on failure.
int lfs_setattrs(lfs_t *lfs, const char *path,
const struct lfs_attr *attrs, int count);
int lfs_setattr(lfs_t *lfs, const char *path,
uint8_t type, const void *buffer, lfs_size_t size);
/// File operations ///
// Open a file
//
// The mode that the file is opened in is determined
// by the flags, which are values from the enum lfs_open_flags
// that are bitwise-ored together.
// The mode that the file is opened in is determined by the flags, which
// are values from the enum lfs_open_flags that are bitwise-ored together.
//
// Returns a negative error code on failure.
int lfs_file_open(lfs_t *lfs, lfs_file_t *file,
const char *path, int flags);
// Open a file with extra configuration
//
// The mode that the file is opened in is determined by the flags, which
// are values from the enum lfs_open_flags that are bitwise-ored together.
//
// The config struct provides additional config options per file as described
// above. The config struct must be allocated while the file is open, and the
// config struct must be zeroed for defaults and backwards compatibility.
//
// Returns a negative error code on failure.
int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file,
const char *path, int flags,
const struct lfs_file_config *config);
// Close a file
//
// Any pending writes are written out to storage as though
@@ -503,30 +534,6 @@ int lfs_file_rewind(lfs_t *lfs, lfs_file_t *file);
// Returns the size of the file, or a negative error code on failure.
lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file);
// Get custom attributes attached to a file
//
// Attributes are looked up based on the type id. If the stored attribute is
// smaller than the buffer, it is padded with zeros. It the stored attribute
// is larger than the buffer, LFS_ERR_RANGE is returned.
//
// Returns a negative error code on failure.
int lfs_file_getattrs(lfs_t *lfs, lfs_file_t *file,
const struct lfs_attr *attrs, int count);
// Set custom attributes on a file
//
// The array of attributes will be used to update the attributes stored on
// disk based on their type id. Unspecified attributes are left unmodified.
// Specifying an attribute with zero size deletes the attribute.
//
// Note: Attributes are not written out until a call to lfs_file_sync
// or lfs_file_close and must be allocated until the file is closed or
// lfs_file_setattrs is called with a count of zero.
//
// Returns a negative error code on failure.
int lfs_file_setattrs(lfs_t *lfs, lfs_file_t *file,
const struct lfs_attr *attrs, int count);
/// Directory operations ///
@@ -583,8 +590,10 @@ int lfs_dir_rewind(lfs_t *lfs, lfs_dir_t *dir);
// smaller than the buffer, it is padded with zeros. It the stored attribute
// is larger than the buffer, LFS_ERR_RANGE is returned.
//
// TODO doc
// Returns a negative error code on failure.
int lfs_fs_getattrs(lfs_t *lfs, const struct lfs_attr *attrs, int count);
lfs_ssize_t lfs_fs_getattr(lfs_t *lfs,
uint8_t type, void *buffer, lfs_size_t size);
// Set custom attributes on the filesystem
//
@@ -594,8 +603,10 @@ int lfs_fs_getattrs(lfs_t *lfs, const struct lfs_attr *attrs, int count);
//
// Note: Filesystem level attributes are not available for wear-leveling
//
// TODO doc
// Returns a negative error code on failure.
int lfs_fs_setattrs(lfs_t *lfs, const struct lfs_attr *attrs, int count);
int lfs_fs_setattr(lfs_t *lfs,
uint8_t type, const void *buffer, lfs_size_t size);
// Finds the current size of the filesystem
//