Skip to content

Commit 6f73171

Browse files
amir73iljankara
authored andcommitted
fsnotify: allow fsnotify_{peek,remove}_first_event with empty queue
Current code has an assumtion that fsnotify_notify_queue_is_empty() is called to verify that queue is not empty before trying to peek or remove an event from queue. Remove this assumption by moving the fsnotify_notify_queue_is_empty() into the functions, allow them to return NULL value and check return value by all callers. This is a prep patch for multi event queues. Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Amir Goldstein <[email protected]> Signed-off-by: Jan Kara <[email protected]>
1 parent 1e28eed commit 6f73171

File tree

4 files changed

+44
-37
lines changed

4 files changed

+44
-37
lines changed

fs/notify/fanotify/fanotify_user.c

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -100,24 +100,30 @@ static struct fanotify_event *get_one_event(struct fsnotify_group *group,
100100
{
101101
size_t event_size = FAN_EVENT_METADATA_LEN;
102102
struct fanotify_event *event = NULL;
103+
struct fsnotify_event *fsn_event;
103104
unsigned int fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS);
104105

105106
pr_debug("%s: group=%p count=%zd\n", __func__, group, count);
106107

107108
spin_lock(&group->notification_lock);
108-
if (fsnotify_notify_queue_is_empty(group))
109+
fsn_event = fsnotify_peek_first_event(group);
110+
if (!fsn_event)
109111
goto out;
110112

111-
if (fid_mode) {
112-
event_size += fanotify_event_info_len(fid_mode,
113-
FANOTIFY_E(fsnotify_peek_first_event(group)));
114-
}
113+
event = FANOTIFY_E(fsn_event);
114+
if (fid_mode)
115+
event_size += fanotify_event_info_len(fid_mode, event);
115116

116117
if (event_size > count) {
117118
event = ERR_PTR(-EINVAL);
118119
goto out;
119120
}
120-
event = FANOTIFY_E(fsnotify_remove_first_event(group));
121+
122+
/*
123+
* Held the notification_lock the whole time, so this is the
124+
* same event we peeked above.
125+
*/
126+
fsnotify_remove_first_event(group);
121127
if (fanotify_is_perm_event(event->mask))
122128
FANOTIFY_PERM(event)->state = FAN_EVENT_REPORTED;
123129
out:
@@ -573,6 +579,7 @@ static ssize_t fanotify_write(struct file *file, const char __user *buf, size_t
573579
static int fanotify_release(struct inode *ignored, struct file *file)
574580
{
575581
struct fsnotify_group *group = file->private_data;
582+
struct fsnotify_event *fsn_event;
576583

577584
/*
578585
* Stop new events from arriving in the notification queue. since
@@ -601,13 +608,12 @@ static int fanotify_release(struct inode *ignored, struct file *file)
601608
* dequeue them and set the response. They will be freed once the
602609
* response is consumed and fanotify_get_response() returns.
603610
*/
604-
while (!fsnotify_notify_queue_is_empty(group)) {
605-
struct fanotify_event *event;
611+
while ((fsn_event = fsnotify_remove_first_event(group))) {
612+
struct fanotify_event *event = FANOTIFY_E(fsn_event);
606613

607-
event = FANOTIFY_E(fsnotify_remove_first_event(group));
608614
if (!(event->mask & FANOTIFY_PERM_EVENTS)) {
609615
spin_unlock(&group->notification_lock);
610-
fsnotify_destroy_event(group, &event->fse);
616+
fsnotify_destroy_event(group, fsn_event);
611617
} else {
612618
finish_permission_event(group, FANOTIFY_PERM(event),
613619
FAN_ALLOW);

fs/notify/inotify/inotify_user.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,10 +146,9 @@ static struct fsnotify_event *get_one_event(struct fsnotify_group *group,
146146
size_t event_size = sizeof(struct inotify_event);
147147
struct fsnotify_event *event;
148148

149-
if (fsnotify_notify_queue_is_empty(group))
150-
return NULL;
151-
152149
event = fsnotify_peek_first_event(group);
150+
if (!event)
151+
return NULL;
153152

154153
pr_debug("%s: group=%p event=%p\n", __func__, group, event);
155154

fs/notify/notification.c

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,6 @@ u32 fsnotify_get_cookie(void)
4747
}
4848
EXPORT_SYMBOL_GPL(fsnotify_get_cookie);
4949

50-
/* return true if the notify queue is empty, false otherwise */
51-
bool fsnotify_notify_queue_is_empty(struct fsnotify_group *group)
52-
{
53-
assert_spin_locked(&group->notification_lock);
54-
return list_empty(&group->notification_list) ? true : false;
55-
}
56-
5750
void fsnotify_destroy_event(struct fsnotify_group *group,
5851
struct fsnotify_event *event)
5952
{
@@ -141,33 +134,36 @@ void fsnotify_remove_queued_event(struct fsnotify_group *group,
141134
}
142135

143136
/*
144-
* Remove and return the first event from the notification list. It is the
145-
* responsibility of the caller to destroy the obtained event
137+
* Return the first event on the notification list without removing it.
138+
* Returns NULL if the list is empty.
146139
*/
147-
struct fsnotify_event *fsnotify_remove_first_event(struct fsnotify_group *group)
140+
struct fsnotify_event *fsnotify_peek_first_event(struct fsnotify_group *group)
148141
{
149-
struct fsnotify_event *event;
150-
151142
assert_spin_locked(&group->notification_lock);
152143

153-
pr_debug("%s: group=%p\n", __func__, group);
144+
if (fsnotify_notify_queue_is_empty(group))
145+
return NULL;
154146

155-
event = list_first_entry(&group->notification_list,
156-
struct fsnotify_event, list);
157-
fsnotify_remove_queued_event(group, event);
158-
return event;
147+
return list_first_entry(&group->notification_list,
148+
struct fsnotify_event, list);
159149
}
160150

161151
/*
162-
* This will not remove the event, that must be done with
163-
* fsnotify_remove_first_event()
152+
* Remove and return the first event from the notification list. It is the
153+
* responsibility of the caller to destroy the obtained event
164154
*/
165-
struct fsnotify_event *fsnotify_peek_first_event(struct fsnotify_group *group)
155+
struct fsnotify_event *fsnotify_remove_first_event(struct fsnotify_group *group)
166156
{
167-
assert_spin_locked(&group->notification_lock);
157+
struct fsnotify_event *event = fsnotify_peek_first_event(group);
168158

169-
return list_first_entry(&group->notification_list,
170-
struct fsnotify_event, list);
159+
if (!event)
160+
return NULL;
161+
162+
pr_debug("%s: group=%p event=%p\n", __func__, group, event);
163+
164+
fsnotify_remove_queued_event(group, event);
165+
166+
return event;
171167
}
172168

173169
/*

include/linux/fsnotify_backend.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,13 @@ static inline void fsnotify_queue_overflow(struct fsnotify_group *group)
495495
fsnotify_add_event(group, group->overflow_event, NULL);
496496
}
497497

498-
/* true if the group notification queue is empty */
498+
static inline bool fsnotify_notify_queue_is_empty(struct fsnotify_group *group)
499+
{
500+
assert_spin_locked(&group->notification_lock);
501+
502+
return list_empty(&group->notification_list);
503+
}
504+
499505
extern bool fsnotify_notify_queue_is_empty(struct fsnotify_group *group);
500506
/* return, but do not dequeue the first event on the notification queue */
501507
extern struct fsnotify_event *fsnotify_peek_first_event(struct fsnotify_group *group);

0 commit comments

Comments
 (0)