diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c
index 9b970359570a..7032083df62a 100644
--- a/fs/notify/fanotify/fanotify.c
+++ b/fs/notify/fanotify/fanotify.c
@@ -111,6 +111,16 @@ static bool fanotify_name_event_equal(struct fanotify_name_event *fne1,
return fanotify_info_equal(info1, info2);
}
+static bool fanotify_error_event_equal(struct fanotify_error_event *fee1,
+ struct fanotify_error_event *fee2)
+{
+ /* Error events against the same file system are always merged. */
+ if (!fanotify_fsid_equal(&fee1->fsid, &fee2->fsid))
+ return false;
+
+ return true;
+}
+
static bool fanotify_should_merge(struct fanotify_event *old,
struct fanotify_event *new)
{@@ -141,6 +151,9 @@ static bool fanotify_should_merge(struct fanotify_event *old,
case FANOTIFY_EVENT_TYPE_FID_NAME:
return fanotify_name_event_equal(FANOTIFY_NE(old),
FANOTIFY_NE(new));
+ case FANOTIFY_EVENT_TYPE_FS_ERROR:
+ return fanotify_error_event_equal(FANOTIFY_EE(old),
+ FANOTIFY_EE(new));
default:
WARN_ON_ONCE(1);
}@@ -148,6 +161,22 @@ static bool fanotify_should_merge(struct fanotify_event *old,
return false;
}
+static void fanotify_merge_error_event(struct fanotify_error_event *dest,
+ struct fanotify_error_event *origin)
+{
+ dest->err_count++;
+}
+
+static void fanotify_merge_event(struct fanotify_event *dest,
+ struct fanotify_event *origin)
+{
+ dest->mask |= origin->mask;
+
+ if (origin->type == FANOTIFY_EVENT_TYPE_FS_ERROR)
+ fanotify_merge_error_event(FANOTIFY_EE(dest),
+ FANOTIFY_EE(origin));
+}
+
/* Limit event merges to limit CPU overhead per event */
#define FANOTIFY_MAX_MERGE_EVENTS 128
@@ -175,7 +204,7 @@ static int fanotify_merge(struct fsnotify_group *group,
if (++i > FANOTIFY_MAX_MERGE_EVENTS)
break;
if (fanotify_should_merge(old, new)) {
- old->mask |= new->mask;
+ fanotify_merge_event(old, new);
return 1;
}
}@@ -577,7 +606,8 @@ static struct fanotify_event *fanotify_alloc_name_event(struct inode *id,
static struct fanotify_event *fanotify_alloc_error_event(
struct fsnotify_group *group,
__kernel_fsid_t *fsid,
- const void *data, int data_type)
+ const void *data, int data_type,
+ unsigned int *hash)
{
struct fs_error_report *report =
fsnotify_data_error_report(data, data_type);@@ -591,6 +621,9 @@ static struct fanotify_event *fanotify_alloc_error_event(
return NULL;
fee->fae.type = FANOTIFY_EVENT_TYPE_FS_ERROR;
+ fee->err_count = 1;
+
+ *hash ^= fanotify_hash_fsid(fsid);
return &fee->fae;
}