diff --git a/security/integrity/Makefile b/security/integrity/Makefile
index 0c175a567ac..c856ed10fba 100644
--- a/security/integrity/Makefile
+++ b/security/integrity/Makefile
@@ -11,7 +11,8 @@ integrity-$(CONFIG_INTEGRITY_SIGNATURE) += digsig.o
 integrity-$(CONFIG_INTEGRITY_ASYMMETRIC_KEYS) += digsig_asymmetric.o
 integrity-$(CONFIG_INTEGRITY_PLATFORM_KEYRING) += platform_certs/platform_keyring.o
 integrity-$(CONFIG_INTEGRITY_MACHINE_KEYRING) += platform_certs/machine_keyring.o
-integrity-$(CONFIG_INTEGRITY_DIGEST_CACHE) += digest_cache.o
+integrity-$(CONFIG_INTEGRITY_DIGEST_CACHE) += digest_cache.o \
+					      digest_cache_iter.o
 integrity-$(CONFIG_LOAD_UEFI_KEYS) += platform_certs/efi_parser.o \
 				      platform_certs/load_uefi.o \
 				      platform_certs/keyring_handler.o
diff --git a/security/integrity/digest_cache.h b/security/integrity/digest_cache.h
index 01cd70f9850..cd5c913cf7a 100644
--- a/security/integrity/digest_cache.h
+++ b/security/integrity/digest_cache.h
@@ -71,6 +71,7 @@ int digest_cache_init_htable(struct digest_cache *digest_cache,
 int digest_cache_add(struct digest_cache *digest_cache, u8 *digest);
 int digest_cache_lookup(struct digest_cache *digest_cache, u8 *digest,
 			enum hash_algo algo, const char *pathname);
+void digest_cache_iter_dir(struct dentry *repo_dentry);
 #else
 static inline void digest_cache_free(struct digest_cache *digest_cache)
 {
@@ -101,5 +102,9 @@ static inline int digest_cache_lookup(struct digest_cache *digest_cache,
 	return -ENOENT;
 }
 
+static inline void digest_cache_iter_dir(struct dentry *repo_dentry)
+{
+}
+
 #endif /* CONFIG_INTEGRITY_DIGEST_CACHE */
 #endif /* _DIGEST_CACHE_H */
diff --git a/security/integrity/digest_cache_iter.c b/security/integrity/digest_cache_iter.c
new file mode 100644
index 00000000000..f7641e7b365
--- /dev/null
+++ b/security/integrity/digest_cache_iter.c
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Huawei Technologies Duesseldorf GmbH
+ *
+ * Author: Roberto Sassu <roberto.sassu@huawei.com>
+ *
+ * Implement a digest list iterator.
+ */
+
+#include <linux/fs.h>
+#include <linux/xattr.h>
+#include <linux/vmalloc.h>
+#include <linux/kernel_read_file.h>
+
+#include "integrity.h"
+
+#ifdef pr_fmt
+#undef pr_fmt
+#endif
+#define pr_fmt(fmt) "DIGEST CACHE ITER: "fmt
+
+static bool iterated;
+/* Ensure there is only one iteration over digest lists, make others wait. */
+DEFINE_MUTEX(iterate_mutex);
+
+struct dir_entry {
+	struct list_head list;
+	char name[];
+} __packed;
+
+struct readdir_callback {
+	struct dir_context ctx;
+	struct list_head *head;
+};
+
+/**
+ * digest_cache_iter_digest_list - Callback func to get digest lists in a dir
+ * @__ctx: iterate_dir() context
+ * @name: Name of file in the accessed dir
+ * @namelen: String length of @name
+ * @offset: Current position in the directory stream (see man readdir)
+ * @ino: Inode number
+ * @d_type: File type
+ *
+ * This function stores the names of the files in the containing directory in
+ * a linked list. Those files will be opened to trigger a measurement.
+ *
+ * Return: True to continue processing, false to stop.
+ */
+static bool digest_cache_iter_digest_list(struct dir_context *__ctx,
+					  const char *name, int namelen,
+					  loff_t offset, u64 ino,
+					  unsigned int d_type)
+{
+	struct readdir_callback *ctx = container_of(__ctx, typeof(*ctx), ctx);
+	struct dir_entry *new_entry;
+
+	if (!strcmp(name, ".") || !strcmp(name, ".."))
+		return true;
+
+	if (d_type != DT_REG)
+		return true;
+
+	new_entry = kmalloc(sizeof(*new_entry) + namelen + 1, GFP_KERNEL);
+	if (!new_entry)
+		return true;
+
+	memcpy(new_entry->name, name, namelen);
+	new_entry->name[namelen] = '\0';
+	list_add_tail(&new_entry->list, ctx->head);
+	return true;
+}
+
+/**
+ * digest_cache_iter_dir - Iterate over all files in the same digest list dir
+ * @digest_list_dentry: Digest list dentry
+ *
+ * This function iterates over all files in the directory containing the digest
+ * list provided as argument. It helps to measure digest lists in a
+ * deterministic order and make a TPM PCR predictable.
+ */
+void digest_cache_iter_dir(struct dentry *digest_list_dentry)
+{
+	struct file *dir_file;
+	struct readdir_callback buf = {
+		.ctx.actor = digest_cache_iter_digest_list,
+	};
+	struct dir_entry *p, *q;
+	struct file *file;
+	char *path_str = NULL, *dir_path_str = NULL;
+	void *data;
+	LIST_HEAD(head);
+	char *ptr;
+	int ret;
+
+	if (iterated)
+		return;
+
+	mutex_lock(&iterate_mutex);
+	if (iterated)
+		goto out;
+
+	iterated = true;
+
+	ret = vfs_getxattr_alloc(&nop_mnt_idmap, digest_list_dentry,
+				 XATTR_NAME_DIGEST_LIST, &path_str, 0,
+				 GFP_NOFS);
+	if (ret <= 0) {
+		pr_debug("%s xattr not found in %s\n", XATTR_NAME_DIGEST_LIST,
+			 digest_list_dentry->d_name.name);
+		goto out;
+	}
+
+	pr_debug("Found %s xattr in %s, digest list: %s\n",
+		 XATTR_NAME_DIGEST_LIST, digest_list_dentry->d_name.name,
+		 path_str);
+
+	ptr = strrchr(path_str, '/');
+	if (!ptr)
+		goto out;
+
+	dir_path_str = kstrndup(path_str, ptr - path_str, GFP_KERNEL);
+	if (!dir_path_str)
+		goto out;
+
+	dir_file = filp_open(dir_path_str, O_RDONLY, 0);
+
+	if (IS_ERR(dir_file)) {
+		pr_debug("Cannot access %s\n", dir_path_str);
+		goto out;
+	}
+
+	buf.head = &head;
+	iterate_dir(dir_file, &buf.ctx);
+	list_for_each_entry_safe(p, q, &head, list) {
+		pr_debug("Prefetching digest list %s/%s\n", dir_path_str,
+			 p->name);
+
+		file = file_open_root(&dir_file->f_path, p->name, O_RDONLY, 0);
+		if (IS_ERR(file))
+			continue;
+
+		data = NULL;
+
+		ret = kernel_read_file(file, 0, &data, INT_MAX, NULL,
+				       READING_DIGEST_LIST);
+		if (ret >= 0)
+			vfree(data);
+
+		fput(file);
+		list_del(&p->list);
+		kfree(p);
+	}
+
+	fput(dir_file);
+out:
+	mutex_unlock(&iterate_mutex);
+	kfree(path_str);
+	kfree(dir_path_str);
+}
