Skip to content

Commit

Permalink
lib: Add LCFS_BUILD_NO_INLINE option to build flags
Browse files Browse the repository at this point in the history
Unless you pass this to lcfs_load_node_from_file() then it will
automatically add the file content for small files to the lcfs_nodes,
which means that the file data will be stored in the erofs image instead
of in a separate file in the basedir.

The limit for small files is 64 bytes, which is the size of a sha256
digest in hex form. That is typically the size of a redirect xattr
that would be used otherwise, so the end result is that we always get
a smaller image if we inline these. 64 is also the typical size of a
erofs inode entry, so this will inline well in the inode table.

Signed-off-by: Alexander Larsson <[email protected]>
  • Loading branch information
alexlarsson committed Sep 13, 2023
1 parent 7412067 commit d636bee
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 9 deletions.
6 changes: 6 additions & 0 deletions libcomposefs/lcfs-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@
#include "lcfs-fsverity.h"
#include "hash.h"

/* When using LCFS_BUILD_INLINE_SMALL in lcfs_load_node_from_file() inline files below this size
* We pick 64 which is the size of a sha256 digest that would otherwise be used as a redirect
* xattr, so the inlined file is smaller.
*/
#define LCFS_BUILD_INLINE_FILE_SIZE_LIMIT 64

#define ALIGN_TO(_offset, _align_size) \
(((_offset) + _align_size - 1) & ~(_align_size - 1))

Expand Down
66 changes: 58 additions & 8 deletions libcomposefs/lcfs-writer.c
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,30 @@ int lcfs_node_set_fsverity_from_fd(struct lcfs_node_s *node, int fd)
return lcfs_node_set_fsverity_from_content(node, &_fd, fsverity_read_cb);
}

static int read_content(int fd, size_t size, uint8_t *buf)
{
int bytes_read;

while (size > 0) {
do
bytes_read = read(fd, buf, size);
while (bytes_read < 0 && errno == EINTR);

if (bytes_read == 0)
break;

size -= bytes_read;
buf += bytes_read;
}

if (size > 0) {
errno = ENODATA;
return -1;
}

return 0;
}

struct lcfs_node_s *lcfs_load_node_from_file(int dirfd, const char *fname,
int buildflags)
{
Expand All @@ -548,7 +572,8 @@ struct lcfs_node_s *lcfs_load_node_from_file(int dirfd, const char *fname,
int r;

if (buildflags & ~(LCFS_BUILD_SKIP_XATTRS | LCFS_BUILD_USE_EPOCH |
LCFS_BUILD_SKIP_DEVICES | LCFS_BUILD_COMPUTE_DIGEST)) {
LCFS_BUILD_SKIP_DEVICES | LCFS_BUILD_COMPUTE_DIGEST |
LCFS_BUILD_NO_INLINE)) {
errno = EINVAL;
return NULL;
}
Expand All @@ -568,17 +593,42 @@ struct lcfs_node_s *lcfs_load_node_from_file(int dirfd, const char *fname,
ret->inode.st_size = sb.st_size;

if ((sb.st_mode & S_IFMT) == S_IFREG) {
if (sb.st_size != 0 && (buildflags & LCFS_BUILD_COMPUTE_DIGEST) != 0) {
int fd = openat(dirfd, fname, O_RDONLY | O_CLOEXEC);
bool compute_digest = (buildflags & LCFS_BUILD_COMPUTE_DIGEST) != 0;
bool no_inline = (buildflags & LCFS_BUILD_NO_INLINE) != 0;
bool is_zerosized = sb.st_size == 0;
bool do_digest = !is_zerosized && compute_digest;
bool do_inline = !is_zerosized && !no_inline &&
sb.st_size <= LCFS_BUILD_INLINE_FILE_SIZE_LIMIT;

if (do_digest || do_inline) {
cleanup_fd int fd =
openat(dirfd, fname, O_RDONLY | O_CLOEXEC);
if (fd < 0) {
lcfs_node_unref(ret);
return NULL;
}
r = lcfs_node_set_fsverity_from_fd(ret, fd);
close(fd);
if (r < 0) {
lcfs_node_unref(ret);
return NULL;
if (do_digest) {
r = lcfs_node_set_fsverity_from_fd(ret, fd);
if (r < 0) {
lcfs_node_unref(ret);
return NULL;
}
/* In case we re-read below */
lseek(fd, 0, SEEK_SET);
}
if (do_inline) {
uint8_t buf[LCFS_BUILD_INLINE_FILE_SIZE_LIMIT];

r = read_content(fd, sb.st_size, buf);
if (r < 0) {
lcfs_node_unref(ret);
return NULL;
}
r = lcfs_node_set_content(ret, buf, sb.st_size);
if (r < 0) {
lcfs_node_unref(ret);
return NULL;
}
}
}
}
Expand Down
1 change: 1 addition & 0 deletions libcomposefs/lcfs-writer.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ enum {
LCFS_BUILD_USE_EPOCH = (1 << 1),
LCFS_BUILD_SKIP_DEVICES = (1 << 2),
LCFS_BUILD_COMPUTE_DIGEST = (1 << 3),
LCFS_BUILD_NO_INLINE = (1 << 4),
};

enum lcfs_format_t {
Expand Down
3 changes: 2 additions & 1 deletion tools/mkcomposefs.c
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,8 @@ static int fill_payload(struct lcfs_node_s *node, const char *path, size_t len,
ret = lcfs_node_set_payload(node, target);
if (ret < 0)
return ret;
} else if ((lcfs_node_get_mode(node) & S_IFMT) == S_IFREG) {
} else if ((lcfs_node_get_mode(node) & S_IFMT) == S_IFREG &&
lcfs_node_get_content(node) == NULL) {
const uint8_t *digest = NULL;

if (by_digest)
Expand Down

0 comments on commit d636bee

Please sign in to comment.