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.

Reply via email to