Cache the FIT image fit_open() calls to avoid loading the same FIT image
twice. This is very useful if the same FIT image is used to provide the
base devicetree, kernel and initrd as well as devicetree overlays.

Signed-off-by: Marco Felsch <m.fel...@pengutronix.de>
---
 common/image-fit.c  | 32 ++++++++++++++++++++++++++++++++
 include/image-fit.h |  4 ++++
 2 files changed, 36 insertions(+)

diff --git a/common/image-fit.c b/common/image-fit.c
index 
c9d08d25f723665e5203d8e8372255a39bf739de..2cde844e46a61f412a46c2c7bb79d833153e5344
 100644
--- a/common/image-fit.c
+++ b/common/image-fit.c
@@ -16,6 +16,7 @@
 #include <fs.h>
 #include <malloc.h>
 #include <linux/ctype.h>
+#include <linux/refcount.h>
 #include <asm/byteorder.h>
 #include <errno.h>
 #include <linux/err.h>
@@ -33,6 +34,8 @@
 #define CHECK_LEVEL_SIG 2
 #define CHECK_LEVEL_MAX 3
 
+static LIST_HEAD(open_fits);
+
 static uint32_t dt_struct_advance(struct fdt_header *f, uint32_t dt, int size)
 {
        dt += size;
@@ -902,6 +905,18 @@ void *fit_open_configuration(struct fit_handle *handle, 
const char *name,
        return conf_node;
 }
 
+static struct fit_handle *fit_get_handle(const char *filename)
+{
+       struct fit_handle *handle;
+
+       list_for_each_entry(handle, &open_fits, entry) {
+               if (!strcmp(filename, handle->filename))
+                       return handle;
+       }
+
+       return NULL;
+}
+
 static int fit_do_open(struct fit_handle *handle)
 {
        const char *desc = "(no description)";
@@ -951,6 +966,8 @@ struct fit_handle *fit_open_buf(const void *buf, size_t 
size, bool verbose,
        handle->size = size;
        handle->verify = verify;
 
+       refcount_set(&handle->users, 1);
+
        ret = fit_do_open(handle);
        if (ret) {
                fit_close(handle);
@@ -985,6 +1002,12 @@ struct fit_handle *fit_open(const char *_filename, bool 
verbose,
                return ERR_PTR(-errno);
        }
 
+       handle = fit_get_handle(filename);
+       if (handle) {
+               refcount_inc(&handle->users);
+               return handle;
+       }
+
        handle = xzalloc(sizeof(struct fit_handle));
 
        handle->verbose = verbose;
@@ -1002,6 +1025,9 @@ struct fit_handle *fit_open(const char *_filename, bool 
verbose,
        handle->fit = handle->fit_alloc;
        handle->filename = filename;
 
+       refcount_set(&handle->users, 1);
+       list_add(&handle->entry, &open_fits);
+
        ret = fit_do_open(handle);
        if (ret) {
                fit_close(handle);
@@ -1013,9 +1039,15 @@ struct fit_handle *fit_open(const char *_filename, bool 
verbose,
 
 static void __fit_close(struct fit_handle *handle)
 {
+       if (!refcount_dec_and_test(&handle->users))
+               return;
+
        if (handle->root)
                of_delete_node(handle->root);
 
+       if (handle->filename)
+               list_del(&handle->entry);
+
        free(handle->filename);
        free(handle->fit_alloc);
 }
diff --git a/include/image-fit.h b/include/image-fit.h
index 
68f70f4365cb7a650596263086f7de2209d5957e..f9791ff251c554eda56bf3af98c8abceb056a176
 100644
--- a/include/image-fit.h
+++ b/include/image-fit.h
@@ -7,6 +7,7 @@
 #define __IMAGE_FIT_H__
 
 #include <linux/types.h>
+#include <linux/refcount.h>
 #include <bootm.h>
 
 struct fit_handle {
@@ -15,6 +16,9 @@ struct fit_handle {
        size_t size;
        char *filename;
 
+       struct list_head entry;
+       refcount_t users;
+
        bool verbose;
        enum bootm_verify verify;
 

-- 
2.39.5


Reply via email to