This patch optimizes RAM utilization of bootfs by eliminating unnecessary copy of data. It does so by pointing created file nodes to existing data offset in memory which is part of area where kernel is copied after decompression.
In essence we add new flag rn_owns_buf to RAMFS ramfs_node to track if we can actually free memory whenever it happens. By default rn_owns_buf is set to true but new function ramfs_set_file_data called from unpack_bootfs() sets it to false. The savings of RAM are equal to the size of build/release/bootfs.bin which means we save around 700K with ZFS images, 0 with ROSF and as much as application code size with RAMFS where the improvement is most significant especially with Java images. Please note that file data referenced by nodes created during unpack_bootfs() would point to wherever bootfs.bin data is in the uncompressed kernel area which means it is most likely not aligned which possibly means slower access. This could be improved by making individual files aligned in bootfs.bin. Fixes #977 Signed-off-by: Waldemar Kozaczuk <jwkozac...@gmail.com> --- fs/ramfs/ramfs.h | 1 + fs/ramfs/ramfs_vnops.cc | 38 ++++++++++++++++++++++++++++++++++---- fs/vfs/main.cc | 18 ++++++++++++++---- 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/fs/ramfs/ramfs.h b/fs/ramfs/ramfs.h index f21ff4bd..88ccbe72 100644 --- a/fs/ramfs/ramfs.h +++ b/fs/ramfs/ramfs.h @@ -58,6 +58,7 @@ struct ramfs_node { struct timespec rn_atime; struct timespec rn_mtime; int rn_mode; + bool rn_owns_buf; }; struct ramfs_node *ramfs_allocate_node(const char *name, int type); diff --git a/fs/ramfs/ramfs_vnops.cc b/fs/ramfs/ramfs_vnops.cc index cf1ae272..9291a4ec 100644 --- a/fs/ramfs/ramfs_vnops.cc +++ b/fs/ramfs/ramfs_vnops.cc @@ -94,6 +94,7 @@ ramfs_allocate_node(const char *name, int type) np->rn_mode = S_IFREG|0777; set_times_to_now(&(np->rn_ctime), &(np->rn_atime), &(np->rn_mtime)); + np->rn_owns_buf = true; return np; } @@ -101,7 +102,7 @@ ramfs_allocate_node(const char *name, int type) void ramfs_free_node(struct ramfs_node *np) { - if (np->rn_buf != NULL) + if (np->rn_buf != NULL && np->rn_owns_buf) free(np->rn_buf); free(np->rn_name); @@ -336,7 +337,8 @@ ramfs_truncate(struct vnode *vp, off_t length) if (length == 0) { if (np->rn_buf != NULL) { - free(np->rn_buf); + if(np->rn_owns_buf) + free(np->rn_buf); np->rn_buf = NULL; np->rn_bufsize = 0; } @@ -348,10 +350,12 @@ ramfs_truncate(struct vnode *vp, off_t length) return EIO; if (np->rn_size != 0) { memcpy(new_buf, np->rn_buf, vp->v_size); - free(np->rn_buf); + if(np->rn_owns_buf) + free(np->rn_buf); } np->rn_buf = (char *) new_buf; np->rn_bufsize = new_size; + np->rn_owns_buf = true; } np->rn_size = length; vp->v_size = length; @@ -413,6 +417,30 @@ ramfs_read(struct vnode *vp, struct file *fp, struct uio *uio, int ioflag) return uiomove(np->rn_buf + uio->uio_offset, len, uio); } +int +ramfs_set_file_data(struct vnode *vp, const void *data, size_t size) +{ + struct ramfs_node *np = (ramfs_node *) vp->v_data; + + if (vp->v_type == VDIR) { + return EISDIR; + } + if (vp->v_type != VREG) { + return EINVAL; + } + if (np->rn_buf) { + return EINVAL; + } + + np->rn_buf = (char *) data; + np->rn_bufsize = size; + np->rn_size = size; + vp->v_size = size; + np->rn_owns_buf = false; + + return 0; +} + static int ramfs_write(struct vnode *vp, struct uio *uio, int ioflag) { @@ -448,13 +476,15 @@ ramfs_write(struct vnode *vp, struct uio *uio, int ioflag) return EIO; if (np->rn_size != 0) { memcpy(new_buf, np->rn_buf, vp->v_size); - free(np->rn_buf); + if(np->rn_owns_buf) + free(np->rn_buf); } np->rn_buf = (char *) new_buf; np->rn_bufsize = new_size; } np->rn_size = end_pos; vp->v_size = end_pos; + np->rn_owns_buf = true; } set_times_to_now(&(np->rn_mtime), &(np->rn_ctime)); diff --git a/fs/vfs/main.cc b/fs/vfs/main.cc index c41c6947..cd141117 100644 --- a/fs/vfs/main.cc +++ b/fs/vfs/main.cc @@ -2132,6 +2132,7 @@ struct bootfs_metadata { extern char bootfs_start; +int ramfs_set_file_data(struct vnode *vp, const void *data, size_t size); void unpack_bootfs(void) { struct bootfs_metadata *md = (struct bootfs_metadata *)&bootfs_start; @@ -2173,13 +2174,22 @@ void unpack_bootfs(void) sys_panic("unpack_bootfs failed"); } - ret = write(fd, &bootfs_start + md[i].offset, md[i].size); - if (ret != md[i].size) { - kprintf("write failed, ret = %d, errno = %d\n", - ret, errno); + struct file *fp; + int error = fget(fd, &fp); + if (error) { + kprintf("couldn't fget %s: %d\n", + md[i].name, error); + sys_panic("unpack_bootfs failed"); + } + + struct vnode *vp = fp->f_dentry->d_vnode; + ret = ramfs_set_file_data(vp, &bootfs_start + md[i].offset, md[i].size); + if (ret) { + kprintf("ramfs_set_file_data failed, ret = %d\n", ret); sys_panic("unpack_bootfs failed"); } + fdrop(fp); close(fd); } } -- 2.17.1 -- You received this message because you are subscribed to the Google Groups "OSv Development" group. To unsubscribe from this group and stop receiving emails from it, send an email to osv-dev+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.