diff options
author | Jan Kara <jack@suse.cz> | 2016-10-07 19:56:52 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-10-07 21:46:26 -0400 |
commit | c21dbe20f606219fe54faf555b7bc5565487c58f (patch) | |
tree | 91e57fe4aad1f1358f099521b570d9daf7b6a758 | |
parent | 1404ff3cc3a14cb1fe8535e30b87d20da9513767 (diff) |
fsnotify: convert notification_mutex to a spinlock
notification_mutex is used to protect the list of pending events. As such
there's no reason to use a sleeping lock for it. Convert it to a
spinlock.
[jack@suse.cz: fixed version]
Link: http://lkml.kernel.org/r/1474031567-1831-1-git-send-email-jack@suse.cz
Link: http://lkml.kernel.org/r/1473797711-14111-5-git-send-email-jack@suse.cz
Signed-off-by: Jan Kara <jack@suse.cz>
Reviewed-by: Lino Sanfilippo <LinoSanfilippo@gmx.de>
Tested-by: Guenter Roeck <linux@roeck-us.net>
Cc: Miklos Szeredi <mszeredi@redhat.com>
Cc: Eric Paris <eparis@redhat.com>
Cc: Al Viro <viro@ZenIV.linux.org.uk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | fs/notify/fanotify/fanotify_user.c | 27 | ||||
-rw-r--r-- | fs/notify/group.c | 6 | ||||
-rw-r--r-- | fs/notify/inotify/inotify_user.c | 16 | ||||
-rw-r--r-- | fs/notify/notification.c | 27 | ||||
-rw-r--r-- | include/linux/fsnotify_backend.h | 2 |
5 files changed, 41 insertions, 37 deletions
diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index 46d135c4988f..80091a5dc8c0 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c | |||
@@ -49,12 +49,13 @@ struct kmem_cache *fanotify_perm_event_cachep __read_mostly; | |||
49 | * enough to fit in "count". Return an error pointer if the count | 49 | * enough to fit in "count". Return an error pointer if the count |
50 | * is not large enough. | 50 | * is not large enough. |
51 | * | 51 | * |
52 | * Called with the group->notification_mutex held. | 52 | * Called with the group->notification_lock held. |
53 | */ | 53 | */ |
54 | static struct fsnotify_event *get_one_event(struct fsnotify_group *group, | 54 | static struct fsnotify_event *get_one_event(struct fsnotify_group *group, |
55 | size_t count) | 55 | size_t count) |
56 | { | 56 | { |
57 | BUG_ON(!mutex_is_locked(&group->notification_mutex)); | 57 | BUG_ON(IS_ENABLED(CONFIG_SMP) && |
58 | !spin_is_locked(&group->notification_lock)); | ||
58 | 59 | ||
59 | pr_debug("%s: group=%p count=%zd\n", __func__, group, count); | 60 | pr_debug("%s: group=%p count=%zd\n", __func__, group, count); |
60 | 61 | ||
@@ -64,7 +65,7 @@ static struct fsnotify_event *get_one_event(struct fsnotify_group *group, | |||
64 | if (FAN_EVENT_METADATA_LEN > count) | 65 | if (FAN_EVENT_METADATA_LEN > count) |
65 | return ERR_PTR(-EINVAL); | 66 | return ERR_PTR(-EINVAL); |
66 | 67 | ||
67 | /* held the notification_mutex the whole time, so this is the | 68 | /* held the notification_lock the whole time, so this is the |
68 | * same event we peeked above */ | 69 | * same event we peeked above */ |
69 | return fsnotify_remove_first_event(group); | 70 | return fsnotify_remove_first_event(group); |
70 | } | 71 | } |
@@ -244,10 +245,10 @@ static unsigned int fanotify_poll(struct file *file, poll_table *wait) | |||
244 | int ret = 0; | 245 | int ret = 0; |
245 | 246 | ||
246 | poll_wait(file, &group->notification_waitq, wait); | 247 | poll_wait(file, &group->notification_waitq, wait); |
247 | mutex_lock(&group->notification_mutex); | 248 | spin_lock(&group->notification_lock); |
248 | if (!fsnotify_notify_queue_is_empty(group)) | 249 | if (!fsnotify_notify_queue_is_empty(group)) |
249 | ret = POLLIN | POLLRDNORM; | 250 | ret = POLLIN | POLLRDNORM; |
250 | mutex_unlock(&group->notification_mutex); | 251 | spin_unlock(&group->notification_lock); |
251 | 252 | ||
252 | return ret; | 253 | return ret; |
253 | } | 254 | } |
@@ -268,9 +269,9 @@ static ssize_t fanotify_read(struct file *file, char __user *buf, | |||
268 | 269 | ||
269 | add_wait_queue(&group->notification_waitq, &wait); | 270 | add_wait_queue(&group->notification_waitq, &wait); |
270 | while (1) { | 271 | while (1) { |
271 | mutex_lock(&group->notification_mutex); | 272 | spin_lock(&group->notification_lock); |
272 | kevent = get_one_event(group, count); | 273 | kevent = get_one_event(group, count); |
273 | mutex_unlock(&group->notification_mutex); | 274 | spin_unlock(&group->notification_lock); |
274 | 275 | ||
275 | if (IS_ERR(kevent)) { | 276 | if (IS_ERR(kevent)) { |
276 | ret = PTR_ERR(kevent); | 277 | ret = PTR_ERR(kevent); |
@@ -387,17 +388,17 @@ static int fanotify_release(struct inode *ignored, struct file *file) | |||
387 | * dequeue them and set the response. They will be freed once the | 388 | * dequeue them and set the response. They will be freed once the |
388 | * response is consumed and fanotify_get_response() returns. | 389 | * response is consumed and fanotify_get_response() returns. |
389 | */ | 390 | */ |
390 | mutex_lock(&group->notification_mutex); | 391 | spin_lock(&group->notification_lock); |
391 | while (!fsnotify_notify_queue_is_empty(group)) { | 392 | while (!fsnotify_notify_queue_is_empty(group)) { |
392 | fsn_event = fsnotify_remove_first_event(group); | 393 | fsn_event = fsnotify_remove_first_event(group); |
393 | if (!(fsn_event->mask & FAN_ALL_PERM_EVENTS)) { | 394 | if (!(fsn_event->mask & FAN_ALL_PERM_EVENTS)) { |
394 | mutex_unlock(&group->notification_mutex); | 395 | spin_unlock(&group->notification_lock); |
395 | fsnotify_destroy_event(group, fsn_event); | 396 | fsnotify_destroy_event(group, fsn_event); |
396 | mutex_lock(&group->notification_mutex); | 397 | spin_lock(&group->notification_lock); |
397 | } else | 398 | } else |
398 | FANOTIFY_PE(fsn_event)->response = FAN_ALLOW; | 399 | FANOTIFY_PE(fsn_event)->response = FAN_ALLOW; |
399 | } | 400 | } |
400 | mutex_unlock(&group->notification_mutex); | 401 | spin_unlock(&group->notification_lock); |
401 | 402 | ||
402 | /* Response for all permission events it set, wakeup waiters */ | 403 | /* Response for all permission events it set, wakeup waiters */ |
403 | wake_up(&group->fanotify_data.access_waitq); | 404 | wake_up(&group->fanotify_data.access_waitq); |
@@ -423,10 +424,10 @@ static long fanotify_ioctl(struct file *file, unsigned int cmd, unsigned long ar | |||
423 | 424 | ||
424 | switch (cmd) { | 425 | switch (cmd) { |
425 | case FIONREAD: | 426 | case FIONREAD: |
426 | mutex_lock(&group->notification_mutex); | 427 | spin_lock(&group->notification_lock); |
427 | list_for_each_entry(fsn_event, &group->notification_list, list) | 428 | list_for_each_entry(fsn_event, &group->notification_list, list) |
428 | send_len += FAN_EVENT_METADATA_LEN; | 429 | send_len += FAN_EVENT_METADATA_LEN; |
429 | mutex_unlock(&group->notification_mutex); | 430 | spin_unlock(&group->notification_lock); |
430 | ret = put_user(send_len, (int __user *) p); | 431 | ret = put_user(send_len, (int __user *) p); |
431 | break; | 432 | break; |
432 | } | 433 | } |
diff --git a/fs/notify/group.c b/fs/notify/group.c index b47f7cfdcaa4..fbe3cbebec16 100644 --- a/fs/notify/group.c +++ b/fs/notify/group.c | |||
@@ -45,9 +45,9 @@ static void fsnotify_final_destroy_group(struct fsnotify_group *group) | |||
45 | */ | 45 | */ |
46 | void fsnotify_group_stop_queueing(struct fsnotify_group *group) | 46 | void fsnotify_group_stop_queueing(struct fsnotify_group *group) |
47 | { | 47 | { |
48 | mutex_lock(&group->notification_mutex); | 48 | spin_lock(&group->notification_lock); |
49 | group->shutdown = true; | 49 | group->shutdown = true; |
50 | mutex_unlock(&group->notification_mutex); | 50 | spin_unlock(&group->notification_lock); |
51 | } | 51 | } |
52 | 52 | ||
53 | /* | 53 | /* |
@@ -125,7 +125,7 @@ struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops) | |||
125 | atomic_set(&group->refcnt, 1); | 125 | atomic_set(&group->refcnt, 1); |
126 | atomic_set(&group->num_marks, 0); | 126 | atomic_set(&group->num_marks, 0); |
127 | 127 | ||
128 | mutex_init(&group->notification_mutex); | 128 | spin_lock_init(&group->notification_lock); |
129 | INIT_LIST_HEAD(&group->notification_list); | 129 | INIT_LIST_HEAD(&group->notification_list); |
130 | init_waitqueue_head(&group->notification_waitq); | 130 | init_waitqueue_head(&group->notification_waitq); |
131 | group->max_events = UINT_MAX; | 131 | group->max_events = UINT_MAX; |
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c index b8d08d0d0a4d..69d1ea3d292a 100644 --- a/fs/notify/inotify/inotify_user.c +++ b/fs/notify/inotify/inotify_user.c | |||
@@ -115,10 +115,10 @@ static unsigned int inotify_poll(struct file *file, poll_table *wait) | |||
115 | int ret = 0; | 115 | int ret = 0; |
116 | 116 | ||
117 | poll_wait(file, &group->notification_waitq, wait); | 117 | poll_wait(file, &group->notification_waitq, wait); |
118 | mutex_lock(&group->notification_mutex); | 118 | spin_lock(&group->notification_lock); |
119 | if (!fsnotify_notify_queue_is_empty(group)) | 119 | if (!fsnotify_notify_queue_is_empty(group)) |
120 | ret = POLLIN | POLLRDNORM; | 120 | ret = POLLIN | POLLRDNORM; |
121 | mutex_unlock(&group->notification_mutex); | 121 | spin_unlock(&group->notification_lock); |
122 | 122 | ||
123 | return ret; | 123 | return ret; |
124 | } | 124 | } |
@@ -138,7 +138,7 @@ static int round_event_name_len(struct fsnotify_event *fsn_event) | |||
138 | * enough to fit in "count". Return an error pointer if | 138 | * enough to fit in "count". Return an error pointer if |
139 | * not large enough. | 139 | * not large enough. |
140 | * | 140 | * |
141 | * Called with the group->notification_mutex held. | 141 | * Called with the group->notification_lock held. |
142 | */ | 142 | */ |
143 | static struct fsnotify_event *get_one_event(struct fsnotify_group *group, | 143 | static struct fsnotify_event *get_one_event(struct fsnotify_group *group, |
144 | size_t count) | 144 | size_t count) |
@@ -157,7 +157,7 @@ static struct fsnotify_event *get_one_event(struct fsnotify_group *group, | |||
157 | if (event_size > count) | 157 | if (event_size > count) |
158 | return ERR_PTR(-EINVAL); | 158 | return ERR_PTR(-EINVAL); |
159 | 159 | ||
160 | /* held the notification_mutex the whole time, so this is the | 160 | /* held the notification_lock the whole time, so this is the |
161 | * same event we peeked above */ | 161 | * same event we peeked above */ |
162 | fsnotify_remove_first_event(group); | 162 | fsnotify_remove_first_event(group); |
163 | 163 | ||
@@ -234,9 +234,9 @@ static ssize_t inotify_read(struct file *file, char __user *buf, | |||
234 | 234 | ||
235 | add_wait_queue(&group->notification_waitq, &wait); | 235 | add_wait_queue(&group->notification_waitq, &wait); |
236 | while (1) { | 236 | while (1) { |
237 | mutex_lock(&group->notification_mutex); | 237 | spin_lock(&group->notification_lock); |
238 | kevent = get_one_event(group, count); | 238 | kevent = get_one_event(group, count); |
239 | mutex_unlock(&group->notification_mutex); | 239 | spin_unlock(&group->notification_lock); |
240 | 240 | ||
241 | pr_debug("%s: group=%p kevent=%p\n", __func__, group, kevent); | 241 | pr_debug("%s: group=%p kevent=%p\n", __func__, group, kevent); |
242 | 242 | ||
@@ -300,13 +300,13 @@ static long inotify_ioctl(struct file *file, unsigned int cmd, | |||
300 | 300 | ||
301 | switch (cmd) { | 301 | switch (cmd) { |
302 | case FIONREAD: | 302 | case FIONREAD: |
303 | mutex_lock(&group->notification_mutex); | 303 | spin_lock(&group->notification_lock); |
304 | list_for_each_entry(fsn_event, &group->notification_list, | 304 | list_for_each_entry(fsn_event, &group->notification_list, |
305 | list) { | 305 | list) { |
306 | send_len += sizeof(struct inotify_event); | 306 | send_len += sizeof(struct inotify_event); |
307 | send_len += round_event_name_len(fsn_event); | 307 | send_len += round_event_name_len(fsn_event); |
308 | } | 308 | } |
309 | mutex_unlock(&group->notification_mutex); | 309 | spin_unlock(&group->notification_lock); |
310 | ret = put_user(send_len, (int __user *) p); | 310 | ret = put_user(send_len, (int __user *) p); |
311 | break; | 311 | break; |
312 | } | 312 | } |
diff --git a/fs/notify/notification.c b/fs/notify/notification.c index 7d563dea52a4..8a7a8cd041e8 100644 --- a/fs/notify/notification.c +++ b/fs/notify/notification.c | |||
@@ -63,7 +63,8 @@ EXPORT_SYMBOL_GPL(fsnotify_get_cookie); | |||
63 | /* return true if the notify queue is empty, false otherwise */ | 63 | /* return true if the notify queue is empty, false otherwise */ |
64 | bool fsnotify_notify_queue_is_empty(struct fsnotify_group *group) | 64 | bool fsnotify_notify_queue_is_empty(struct fsnotify_group *group) |
65 | { | 65 | { |
66 | BUG_ON(!mutex_is_locked(&group->notification_mutex)); | 66 | BUG_ON(IS_ENABLED(CONFIG_SMP) && |
67 | !spin_is_locked(&group->notification_lock)); | ||
67 | return list_empty(&group->notification_list) ? true : false; | 68 | return list_empty(&group->notification_list) ? true : false; |
68 | } | 69 | } |
69 | 70 | ||
@@ -95,10 +96,10 @@ int fsnotify_add_event(struct fsnotify_group *group, | |||
95 | 96 | ||
96 | pr_debug("%s: group=%p event=%p\n", __func__, group, event); | 97 | pr_debug("%s: group=%p event=%p\n", __func__, group, event); |
97 | 98 | ||
98 | mutex_lock(&group->notification_mutex); | 99 | spin_lock(&group->notification_lock); |
99 | 100 | ||
100 | if (group->shutdown) { | 101 | if (group->shutdown) { |
101 | mutex_unlock(&group->notification_mutex); | 102 | spin_unlock(&group->notification_lock); |
102 | return 2; | 103 | return 2; |
103 | } | 104 | } |
104 | 105 | ||
@@ -106,7 +107,7 @@ int fsnotify_add_event(struct fsnotify_group *group, | |||
106 | ret = 2; | 107 | ret = 2; |
107 | /* Queue overflow event only if it isn't already queued */ | 108 | /* Queue overflow event only if it isn't already queued */ |
108 | if (!list_empty(&group->overflow_event->list)) { | 109 | if (!list_empty(&group->overflow_event->list)) { |
109 | mutex_unlock(&group->notification_mutex); | 110 | spin_unlock(&group->notification_lock); |
110 | return ret; | 111 | return ret; |
111 | } | 112 | } |
112 | event = group->overflow_event; | 113 | event = group->overflow_event; |
@@ -116,7 +117,7 @@ int fsnotify_add_event(struct fsnotify_group *group, | |||
116 | if (!list_empty(list) && merge) { | 117 | if (!list_empty(list) && merge) { |
117 | ret = merge(list, event); | 118 | ret = merge(list, event); |
118 | if (ret) { | 119 | if (ret) { |
119 | mutex_unlock(&group->notification_mutex); | 120 | spin_unlock(&group->notification_lock); |
120 | return ret; | 121 | return ret; |
121 | } | 122 | } |
122 | } | 123 | } |
@@ -124,7 +125,7 @@ int fsnotify_add_event(struct fsnotify_group *group, | |||
124 | queue: | 125 | queue: |
125 | group->q_len++; | 126 | group->q_len++; |
126 | list_add_tail(&event->list, list); | 127 | list_add_tail(&event->list, list); |
127 | mutex_unlock(&group->notification_mutex); | 128 | spin_unlock(&group->notification_lock); |
128 | 129 | ||
129 | wake_up(&group->notification_waitq); | 130 | wake_up(&group->notification_waitq); |
130 | kill_fasync(&group->fsn_fa, SIGIO, POLL_IN); | 131 | kill_fasync(&group->fsn_fa, SIGIO, POLL_IN); |
@@ -139,7 +140,8 @@ struct fsnotify_event *fsnotify_remove_first_event(struct fsnotify_group *group) | |||
139 | { | 140 | { |
140 | struct fsnotify_event *event; | 141 | struct fsnotify_event *event; |
141 | 142 | ||
142 | BUG_ON(!mutex_is_locked(&group->notification_mutex)); | 143 | BUG_ON(IS_ENABLED(CONFIG_SMP) && |
144 | !spin_is_locked(&group->notification_lock)); | ||
143 | 145 | ||
144 | pr_debug("%s: group=%p\n", __func__, group); | 146 | pr_debug("%s: group=%p\n", __func__, group); |
145 | 147 | ||
@@ -161,7 +163,8 @@ struct fsnotify_event *fsnotify_remove_first_event(struct fsnotify_group *group) | |||
161 | */ | 163 | */ |
162 | struct fsnotify_event *fsnotify_peek_first_event(struct fsnotify_group *group) | 164 | struct fsnotify_event *fsnotify_peek_first_event(struct fsnotify_group *group) |
163 | { | 165 | { |
164 | BUG_ON(!mutex_is_locked(&group->notification_mutex)); | 166 | BUG_ON(IS_ENABLED(CONFIG_SMP) && |
167 | !spin_is_locked(&group->notification_lock)); | ||
165 | 168 | ||
166 | return list_first_entry(&group->notification_list, | 169 | return list_first_entry(&group->notification_list, |
167 | struct fsnotify_event, list); | 170 | struct fsnotify_event, list); |
@@ -175,14 +178,14 @@ void fsnotify_flush_notify(struct fsnotify_group *group) | |||
175 | { | 178 | { |
176 | struct fsnotify_event *event; | 179 | struct fsnotify_event *event; |
177 | 180 | ||
178 | mutex_lock(&group->notification_mutex); | 181 | spin_lock(&group->notification_lock); |
179 | while (!fsnotify_notify_queue_is_empty(group)) { | 182 | while (!fsnotify_notify_queue_is_empty(group)) { |
180 | event = fsnotify_remove_first_event(group); | 183 | event = fsnotify_remove_first_event(group); |
181 | mutex_unlock(&group->notification_mutex); | 184 | spin_unlock(&group->notification_lock); |
182 | fsnotify_destroy_event(group, event); | 185 | fsnotify_destroy_event(group, event); |
183 | mutex_lock(&group->notification_mutex); | 186 | spin_lock(&group->notification_lock); |
184 | } | 187 | } |
185 | mutex_unlock(&group->notification_mutex); | 188 | spin_unlock(&group->notification_lock); |
186 | } | 189 | } |
187 | 190 | ||
188 | /* | 191 | /* |
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index 7268ed076be8..0713e873b1c9 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h | |||
@@ -135,7 +135,7 @@ struct fsnotify_group { | |||
135 | const struct fsnotify_ops *ops; /* how this group handles things */ | 135 | const struct fsnotify_ops *ops; /* how this group handles things */ |
136 | 136 | ||
137 | /* needed to send notification to userspace */ | 137 | /* needed to send notification to userspace */ |
138 | struct mutex notification_mutex; /* protect the notification_list */ | 138 | spinlock_t notification_lock; /* protect the notification_list */ |
139 | struct list_head notification_list; /* list of event_holder this group needs to send to userspace */ | 139 | struct list_head notification_list; /* list of event_holder this group needs to send to userspace */ |
140 | wait_queue_head_t notification_waitq; /* read() on the notification file blocks on this waitq */ | 140 | wait_queue_head_t notification_waitq; /* read() on the notification file blocks on this waitq */ |
141 | unsigned int q_len; /* events on the queue */ | 141 | unsigned int q_len; /* events on the queue */ |