Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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/20210304104826.3993892-2-amir73il@gmail.com
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Jan Kara <jack@suse.cz>

authored by

Amir Goldstein and committed by
Jan Kara
6f73171e 1e28eed1

+48 -41
+16 -10
fs/notify/fanotify/fanotify_user.c
··· 100 100 { 101 101 size_t event_size = FAN_EVENT_METADATA_LEN; 102 102 struct fanotify_event *event = NULL; 103 + struct fsnotify_event *fsn_event; 103 104 unsigned int fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS); 104 105 105 106 pr_debug("%s: group=%p count=%zd\n", __func__, group, count); 106 107 107 108 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) 109 111 goto out; 110 112 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); 115 116 116 117 if (event_size > count) { 117 118 event = ERR_PTR(-EINVAL); 118 119 goto out; 119 120 } 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); 121 127 if (fanotify_is_perm_event(event->mask)) 122 128 FANOTIFY_PERM(event)->state = FAN_EVENT_REPORTED; 123 129 out: ··· 579 573 static int fanotify_release(struct inode *ignored, struct file *file) 580 574 { 581 575 struct fsnotify_group *group = file->private_data; 576 + struct fsnotify_event *fsn_event; 582 577 583 578 /* 584 579 * Stop new events from arriving in the notification queue. since ··· 608 601 * dequeue them and set the response. They will be freed once the 609 602 * response is consumed and fanotify_get_response() returns. 610 603 */ 611 - while (!fsnotify_notify_queue_is_empty(group)) { 612 - struct fanotify_event *event; 604 + while ((fsn_event = fsnotify_remove_first_event(group))) { 605 + struct fanotify_event *event = FANOTIFY_E(fsn_event); 613 606 614 - event = FANOTIFY_E(fsnotify_remove_first_event(group)); 615 607 if (!(event->mask & FANOTIFY_PERM_EVENTS)) { 616 608 spin_unlock(&group->notification_lock); 617 - fsnotify_destroy_event(group, &event->fse); 609 + fsnotify_destroy_event(group, fsn_event); 618 610 } else { 619 611 finish_permission_event(group, FANOTIFY_PERM(event), 620 612 FAN_ALLOW);
+2 -3
fs/notify/inotify/inotify_user.c
··· 146 146 size_t event_size = sizeof(struct inotify_event); 147 147 struct fsnotify_event *event; 148 148 149 - if (fsnotify_notify_queue_is_empty(group)) 150 - return NULL; 151 - 152 149 event = fsnotify_peek_first_event(group); 150 + if (!event) 151 + return NULL; 153 152 154 153 pr_debug("%s: group=%p event=%p\n", __func__, group, event); 155 154
+23 -27
fs/notify/notification.c
··· 47 47 } 48 48 EXPORT_SYMBOL_GPL(fsnotify_get_cookie); 49 49 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 - 57 50 void fsnotify_destroy_event(struct fsnotify_group *group, 58 51 struct fsnotify_event *event) 59 52 { ··· 134 141 } 135 142 136 143 /* 137 - * Remove and return the first event from the notification list. It is the 138 - * responsibility of the caller to destroy the obtained event 139 - */ 140 - struct fsnotify_event *fsnotify_remove_first_event(struct fsnotify_group *group) 141 - { 142 - struct fsnotify_event *event; 143 - 144 - assert_spin_locked(&group->notification_lock); 145 - 146 - pr_debug("%s: group=%p\n", __func__, group); 147 - 148 - event = list_first_entry(&group->notification_list, 149 - struct fsnotify_event, list); 150 - fsnotify_remove_queued_event(group, event); 151 - return event; 152 - } 153 - 154 - /* 155 - * This will not remove the event, that must be done with 156 - * fsnotify_remove_first_event() 144 + * Return the first event on the notification list without removing it. 145 + * Returns NULL if the list is empty. 157 146 */ 158 147 struct fsnotify_event *fsnotify_peek_first_event(struct fsnotify_group *group) 159 148 { 160 149 assert_spin_locked(&group->notification_lock); 161 150 151 + if (fsnotify_notify_queue_is_empty(group)) 152 + return NULL; 153 + 162 154 return list_first_entry(&group->notification_list, 163 155 struct fsnotify_event, list); 156 + } 157 + 158 + /* 159 + * Remove and return the first event from the notification list. It is the 160 + * responsibility of the caller to destroy the obtained event 161 + */ 162 + struct fsnotify_event *fsnotify_remove_first_event(struct fsnotify_group *group) 163 + { 164 + struct fsnotify_event *event = fsnotify_peek_first_event(group); 165 + 166 + if (!event) 167 + return NULL; 168 + 169 + pr_debug("%s: group=%p event=%p\n", __func__, group, event); 170 + 171 + fsnotify_remove_queued_event(group, event); 172 + 173 + return event; 164 174 } 165 175 166 176 /*
+7 -1
include/linux/fsnotify_backend.h
··· 495 495 fsnotify_add_event(group, group->overflow_event, NULL); 496 496 } 497 497 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 + 499 505 extern bool fsnotify_notify_queue_is_empty(struct fsnotify_group *group); 500 506 /* return, but do not dequeue the first event on the notification queue */ 501 507 extern struct fsnotify_event *fsnotify_peek_first_event(struct fsnotify_group *group);