diff --git a/include/linux/digest_cache.h b/include/linux/digest_cache.h
index 9db8128513ca..950f3a58a861 100644
--- a/include/linux/digest_cache.h
+++ b/include/linux/digest_cache.h
@@ -15,6 +15,28 @@
 
 struct digest_cache;
 
+/**
+ * enum digest_cache_event - Events occurring on a digest cache
+ *
+ * This enum lists all the events occurring on a digest cache, to be notified
+ * outside the digest_cache LSM.
+ */
+enum digest_cache_event {
+	DIGEST_CACHE_RESET,
+};
+
+/**
+ * struct digest_cache_event_data - Information on digest cache events
+ * @digest_cache: Digest cache
+ * @inode: Inode for which the digest cache was requested
+ *
+ * This structure holds information about events occurring on a digest cache.
+ */
+struct digest_cache_event_data {
+	struct digest_cache *digest_cache;
+	struct inode *inode;
+};
+
 /**
  * typedef digest_cache_found_t - Digest cache reference as numeric value
  *
@@ -48,6 +70,8 @@ int digest_cache_verif_set(struct file *file, const char *verif_id, void *data,
 			   size_t size);
 void *digest_cache_verif_get(struct digest_cache *digest_cache,
 			     const char *verif_id);
+int digest_cache_register_notifier(struct notifier_block *nb);
+int digest_cache_unregister_notifier(struct notifier_block *nb);
 
 #else
 static inline struct digest_cache *digest_cache_get(struct dentry *dentry)
@@ -79,5 +103,15 @@ static inline void *digest_cache_verif_get(struct digest_cache *digest_cache,
 	return NULL;
 }
 
+static inline int digest_cache_register_notifier(struct notifier_block *nb)
+{
+	return -EOPNOTSUPP;
+}
+
+static inline int digest_cache_unregister_notifier(struct notifier_block *nb)
+{
+	return -EOPNOTSUPP;
+}
+
 #endif /* CONFIG_SECURITY_DIGEST_CACHE */
 #endif /* _LINUX_DIGEST_CACHE_H */
diff --git a/security/digest_cache/Makefile b/security/digest_cache/Makefile
index 3d5e600a2c45..7577b099c170 100644
--- a/security/digest_cache/Makefile
+++ b/security/digest_cache/Makefile
@@ -5,7 +5,7 @@
 obj-$(CONFIG_SECURITY_DIGEST_CACHE) += digest_cache.o
 
 digest_cache-y := main.o secfs.o htable.o populate.o modsig.o verif.o dir.o \
-		  reset.o
+		  reset.o notifier.o
 
 digest_cache-y += parsers/tlv.o
 digest_cache-y += parsers/rpm.o
diff --git a/security/digest_cache/internal.h b/security/digest_cache/internal.h
index c816929c4743..d930132cc963 100644
--- a/security/digest_cache/internal.h
+++ b/security/digest_cache/internal.h
@@ -21,6 +21,19 @@
 #define RESET			4	/* Digest cache to be recreated. */
 #define RESET_USER		5	/* Dig_user pointer to be released. */
 
+/**
+ * struct notify_inode - Structure with inode for which notification is emitted
+ * @list: Linked list
+ * @inode: Inode for which a notification is emitted
+ *
+ * This structure contains an inode for which a notification of a digest cache
+ * event is emitted.
+ */
+struct notify_inode {
+	struct list_head list;
+	struct inode *inode;
+};
+
 /**
  * struct readdir_callback - Structure to store information for dir iteration
  * @ctx: Context structure
@@ -126,6 +139,7 @@ struct htable {
  * @path_str: Path of the digest list the digest cache was created from
  * @flags: Control flags
  * @verif_data: Verification data regarding the digest list
+ * @notify_inodes: List of inodes for which a notification is emitted
  * @mutex: Protect digest cache modifications
  *
  * This structure represents a cache of digests extracted from a digest list.
@@ -137,6 +151,7 @@ struct digest_cache {
 	char *path_str;
 	unsigned long flags;
 	struct list_head verif_data;
+	struct list_head notify_inodes;
 	struct mutex mutex;
 };
 
@@ -261,4 +276,15 @@ void digest_cache_inode_post_setxattr(struct dentry *dentry, const char *name,
 void digest_cache_inode_post_removexattr(struct dentry *dentry,
 					 const char *name);
 
+/* notifier.c */
+int digest_cache_notify_inode_add(struct digest_cache *digest_cache,
+				  struct inode *inode);
+void digest_cache_notify_inodes_free(struct digest_cache *digest_cache);
+void digest_cache_notify(struct digest_cache *digest_cache, struct inode *inode,
+			 enum digest_cache_event event);
+void digest_cache_notify_multiple(struct digest_cache *digest_cache,
+				  enum digest_cache_event event);
+int digest_cache_register_notifier(struct notifier_block *nb);
+int digest_cache_unregister_notifier(struct notifier_block *nb);
+
 #endif /* _DIGEST_CACHE_INTERNAL_H */
diff --git a/security/digest_cache/main.c b/security/digest_cache/main.c
index ce3518a33c80..6fe0864f938f 100644
--- a/security/digest_cache/main.c
+++ b/security/digest_cache/main.c
@@ -51,6 +51,7 @@ static struct digest_cache *digest_cache_alloc_init(char *path_str,
 	INIT_LIST_HEAD(&digest_cache->htables);
 	INIT_LIST_HEAD(&digest_cache->verif_data);
 	INIT_LIST_HEAD(&digest_cache->dir_entries);
+	INIT_LIST_HEAD(&digest_cache->notify_inodes);
 	mutex_init(&digest_cache->mutex);
 
 	pr_debug("New digest cache %s (ref count: %d)\n",
@@ -70,6 +71,7 @@ static void digest_cache_free(struct digest_cache *digest_cache)
 	digest_cache_htable_free(digest_cache);
 	digest_cache_verif_free(digest_cache);
 	digest_cache_dir_free(digest_cache);
+	digest_cache_notify_inodes_free(digest_cache);
 	mutex_destroy(&digest_cache->mutex);
 
 	pr_debug("Freed digest cache %s\n", digest_cache->path_str);
@@ -398,6 +400,7 @@ struct digest_cache *digest_cache_get(struct dentry *dentry)
 	struct digest_cache_security *dig_sec;
 	struct digest_cache *digest_cache = NULL;
 	struct inode *inode = d_backing_inode(dentry);
+	int ret;
 
 	if (!digest_cache_enabled)
 		return NULL;
@@ -420,6 +423,15 @@ struct digest_cache *digest_cache_get(struct dentry *dentry)
 		/* Consume extra reference from digest_cache_create(). */
 		dig_sec->dig_user = digest_cache_new(dentry);
 		up_read(&default_path_sem);
+
+		if (dig_sec->dig_user) {
+			ret = digest_cache_notify_inode_add(dig_sec->dig_user,
+							    inode);
+			if (ret < 0) {
+				digest_cache_put(dig_sec->dig_user);
+				dig_sec->dig_user = NULL;
+			}
+		}
 	}
 
 	if (dig_sec->dig_user)
diff --git a/security/digest_cache/notifier.c b/security/digest_cache/notifier.c
new file mode 100644
index 000000000000..06e4730e4434
--- /dev/null
+++ b/security/digest_cache/notifier.c
@@ -0,0 +1,135 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2024 Huawei Technologies Duesseldorf GmbH
+ *
+ * Author: Roberto Sassu <roberto.sassu@huawei.com>
+ *
+ * Implement the notifier of the digest_cache LSM.
+ */
+
+#define pr_fmt(fmt) "DIGEST CACHE: "fmt
+
+#include "internal.h"
+
+static BLOCKING_NOTIFIER_HEAD(chain);
+
+static const char * const events_str[] = {
+	[DIGEST_CACHE_RESET] = __stringify(DIGEST_CACHE_RESET),
+};
+
+/**
+ * digest_cache_notify_inode_add - Add inode to digest cache notification list
+ * @digest_cache: Digest cache
+ * @inode: Inode to add
+ *
+ * This function adds an inode to the digest cache notification list, so that
+ * notifications are emitted for that inode.
+ *
+ * Return: Zero on success, -ENOMEM on error.
+ */
+int digest_cache_notify_inode_add(struct digest_cache *digest_cache,
+				  struct inode *inode)
+{
+	struct notify_inode *notify_inode;
+
+	notify_inode = kmalloc(sizeof(*notify_inode), GFP_KERNEL);
+	if (!notify_inode)
+		return -ENOMEM;
+
+	notify_inode->inode = inode;
+
+	mutex_lock(&digest_cache->mutex);
+	list_add_tail(&notify_inode->list, &digest_cache->notify_inodes);
+	pr_debug("Added inode %lu to notification list of digest cache %s\n",
+		 inode->i_ino, digest_cache->path_str);
+	mutex_unlock(&digest_cache->mutex);
+	return 0;
+}
+
+/**
+ * digest_cache_notify_inodes_free - Free digest cache notification list
+ * @digest_cache: Digest cache
+ *
+ * This function removes all inodes from the notification list of the passed
+ * digest cache and frees the memory. Does not need locking, since it is called
+ * only at the time the digest cache is freed.
+ */
+void digest_cache_notify_inodes_free(struct digest_cache *digest_cache)
+{
+	struct notify_inode *p, *q;
+
+	list_for_each_entry_safe(p, q, &digest_cache->notify_inodes, list) {
+		list_del(&p->list);
+		pr_debug("Removed inode %lu from notification list of digest cache %s\n",
+			 p->inode->i_ino, digest_cache->path_str);
+		kfree(p);
+	}
+}
+
+/**
+ * digest_cache_notify - Emit notification for an inode
+ * @digest_cache: Digest cache
+ * @inode: Inode for which a digest cache is used
+ * @event: Event to notify
+ *
+ * This function emits a notification of a digest cache event for an affected
+ * inode.
+ */
+void digest_cache_notify(struct digest_cache *digest_cache, struct inode *inode,
+			 enum digest_cache_event event)
+{
+	struct digest_cache_event_data event_data = {
+		.digest_cache = digest_cache,
+		.inode = inode,
+	};
+
+	pr_debug("Notify event %s for inode %lu using digest cache %s\n",
+		 events_str[event], inode->i_ino, digest_cache->path_str);
+
+	blocking_notifier_call_chain(&chain, event, &event_data);
+}
+
+/**
+ * digest_cache_notify_multiple - Emit notification for all inodes in the list
+ * @digest_cache: Digest cache
+ * @event: Event to notify
+ *
+ * This function emits a notification for all inodes in the notification list
+ * of the passed digest cache.
+ */
+void digest_cache_notify_multiple(struct digest_cache *digest_cache,
+				  enum digest_cache_event event)
+{
+	struct notify_inode *p;
+
+	list_for_each_entry(p, &digest_cache->notify_inodes, list)
+		digest_cache_notify(digest_cache, p->inode, event);
+}
+
+/**
+ * digest_cache_register_notifier() - Register a digest cache notifier
+ * @nb: Notifier block with the callback
+ *
+ * This function registers a new notifier for events occurring on digest caches.
+ *
+ * Return: Zero on success, -EEXIST on error.
+ */
+int digest_cache_register_notifier(struct notifier_block *nb)
+{
+	return blocking_notifier_chain_register(&chain, nb);
+}
+EXPORT_SYMBOL(digest_cache_register_notifier);
+
+/**
+ * digest_cache_unregister_notifier() - Unregister a digest cache notifier
+ * @nb: Notifier block with the callback
+ *
+ * This function unregisters a previously registered notifier.
+ *
+ * Return: Zero on success, -ENOENT on error.
+ */
+int digest_cache_unregister_notifier(struct notifier_block *nb)
+{
+	return blocking_notifier_chain_unregister(&chain, nb);
+}
+EXPORT_SYMBOL(digest_cache_unregister_notifier);
diff --git a/security/digest_cache/reset.c b/security/digest_cache/reset.c
index e07222b0e0e8..bb3b4108ba3b 100644
--- a/security/digest_cache/reset.c
+++ b/security/digest_cache/reset.c
@@ -10,6 +10,29 @@
 #define pr_fmt(fmt) "DIGEST CACHE: "fmt
 #include "internal.h"
 
+/**
+ * digest_cache_notify_dir_entry_reset - Notify dir entry reset
+ * @dir: Directory containing the digest lists
+ *
+ * Emit a notification for the directory containing the digest lists about a
+ * reset occurring on a directory entry.
+ */
+
+static void digest_cache_notify_dir_entry_reset(struct inode *dir)
+{
+	struct digest_cache_security *dir_dig_sec;
+
+	dir_dig_sec = digest_cache_get_security(dir);
+	if (unlikely(!dir_dig_sec))
+		return;
+
+	mutex_lock(&dir_dig_sec->dig_owner_mutex);
+	if (dir_dig_sec->dig_owner)
+		digest_cache_notify_multiple(dir_dig_sec->dig_owner,
+					     DIGEST_CACHE_RESET);
+	mutex_unlock(&dir_dig_sec->dig_owner_mutex);
+}
+
 /**
  * digest_cache_reset_owner - Reset dig_owner
  * @inode: Inode of the digest list/directory containing the digest list
@@ -19,6 +42,9 @@
  * (if unset), so that digest_cache_get() and digest_cache_create() respectively
  * release and clear dig_user and dig_owner in the inode security blob. This
  * causes new callers of digest_cache_get() to get a new digest cache.
+ *
+ * After setting RESET, it emits a notification for all inodes using the digest
+ * cache.
  */
 static void digest_cache_reset_owner(struct inode *inode, const char *reason)
 {
@@ -30,9 +56,12 @@ static void digest_cache_reset_owner(struct inode *inode, const char *reason)
 
 	mutex_lock(&dig_sec->dig_owner_mutex);
 	if (dig_sec->dig_owner &&
-	    !test_and_set_bit(RESET, &dig_sec->dig_owner->flags))
+	    !test_and_set_bit(RESET, &dig_sec->dig_owner->flags)) {
 		pr_debug("Resetting %s (dig_owner), reason: %s\n",
 			 dig_sec->dig_owner->path_str, reason);
+		digest_cache_notify_multiple(dig_sec->dig_owner,
+					     DIGEST_CACHE_RESET);
+	}
 	mutex_unlock(&dig_sec->dig_owner_mutex);
 }
 
@@ -55,9 +84,12 @@ static void digest_cache_reset_user(struct inode *inode, const char *reason)
 
 	mutex_lock(&dig_sec->dig_user_mutex);
 	if (dig_sec->dig_user &&
-	    !test_and_set_bit(RESET_USER, &dig_sec->dig_user->flags))
+	    !test_and_set_bit(RESET_USER, &dig_sec->dig_user->flags)) {
 		pr_debug("Resetting %s (dig_user), reason: %s\n",
 			 dig_sec->dig_user->path_str, reason);
+		digest_cache_notify(dig_sec->dig_user, inode,
+				    DIGEST_CACHE_RESET);
+	}
 	mutex_unlock(&dig_sec->dig_user_mutex);
 }
 
@@ -74,11 +106,14 @@ static void digest_cache_reset_user(struct inode *inode, const char *reason)
 int digest_cache_path_truncate(const struct path *path)
 {
 	struct inode *inode = d_backing_inode(path->dentry);
+	struct inode *dir = d_backing_inode(path->dentry->d_parent);
 
 	if (!S_ISREG(inode->i_mode))
 		return 0;
 
 	digest_cache_reset_owner(inode, "file_truncate");
+	/* Dir digest cache users should know a dir entry changed. */
+	digest_cache_notify_dir_entry_reset(dir);
 	return 0;
 }
 
@@ -101,6 +136,9 @@ void digest_cache_file_release(struct file *file)
 	digest_cache_reset_owner(file_inode(file), "file_file_release");
 	if (file->f_mode & FMODE_CREATED)
 		digest_cache_reset_owner(dir, "dir_file_release");
+	else
+		/* Dir digest cache users should know a dir entry changed. */
+		digest_cache_notify_dir_entry_reset(dir);
 }
 
 /**
