aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2016-10-07 19:56:52 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-10-07 21:46:26 -0400
commitc21dbe20f606219fe54faf555b7bc5565487c58f (patch)
tree91e57fe4aad1f1358f099521b570d9daf7b6a758
parent1404ff3cc3a14cb1fe8535e30b87d20da9513767 (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.c27
-rw-r--r--fs/notify/group.c6
-rw-r--r--fs/notify/inotify/inotify_user.c16
-rw-r--r--fs/notify/notification.c27
-rw-r--r--include/linux/fsnotify_backend.h2
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 */
54static struct fsnotify_event *get_one_event(struct fsnotify_group *group, 54static 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 */
46void fsnotify_group_stop_queueing(struct fsnotify_group *group) 46void 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 */
143static struct fsnotify_event *get_one_event(struct fsnotify_group *group, 143static 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 */
64bool fsnotify_notify_queue_is_empty(struct fsnotify_group *group) 64bool 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,
124queue: 125queue:
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 */
162struct fsnotify_event *fsnotify_peek_first_event(struct fsnotify_group *group) 164struct 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 */