diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/notify/dnotify/dnotify.c | 7 | ||||
-rw-r--r-- | fs/notify/fanotify/fanotify.c | 49 | ||||
-rw-r--r-- | fs/notify/fanotify/fanotify.h | 8 | ||||
-rw-r--r-- | fs/notify/fanotify/fanotify_user.c | 43 | ||||
-rw-r--r-- | fs/notify/fsnotify.c | 101 | ||||
-rw-r--r-- | fs/notify/group.c | 6 | ||||
-rw-r--r-- | fs/notify/inotify/inotify_user.c | 4 | ||||
-rw-r--r-- | fs/notify/mark.c | 121 |
8 files changed, 158 insertions, 181 deletions
diff --git a/fs/notify/dnotify/dnotify.c b/fs/notify/dnotify/dnotify.c index cba328315929..63a1ca4b9dee 100644 --- a/fs/notify/dnotify/dnotify.c +++ b/fs/notify/dnotify/dnotify.c | |||
@@ -319,7 +319,11 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg) | |||
319 | dn_mark = container_of(fsn_mark, struct dnotify_mark, fsn_mark); | 319 | dn_mark = container_of(fsn_mark, struct dnotify_mark, fsn_mark); |
320 | spin_lock(&fsn_mark->lock); | 320 | spin_lock(&fsn_mark->lock); |
321 | } else { | 321 | } else { |
322 | fsnotify_add_mark_locked(new_fsn_mark, inode, NULL, 0); | 322 | error = fsnotify_add_mark_locked(new_fsn_mark, inode, NULL, 0); |
323 | if (error) { | ||
324 | mutex_unlock(&dnotify_group->mark_mutex); | ||
325 | goto out_err; | ||
326 | } | ||
323 | spin_lock(&new_fsn_mark->lock); | 327 | spin_lock(&new_fsn_mark->lock); |
324 | fsn_mark = new_fsn_mark; | 328 | fsn_mark = new_fsn_mark; |
325 | dn_mark = new_dn_mark; | 329 | dn_mark = new_dn_mark; |
@@ -345,6 +349,7 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg) | |||
345 | */ | 349 | */ |
346 | if (dn_mark == new_dn_mark) | 350 | if (dn_mark == new_dn_mark) |
347 | destroy = 1; | 351 | destroy = 1; |
352 | error = 0; | ||
348 | goto out; | 353 | goto out; |
349 | } | 354 | } |
350 | 355 | ||
diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c index 09640b546363..54cf2d21b547 100644 --- a/fs/notify/fanotify/fanotify.c +++ b/fs/notify/fanotify/fanotify.c | |||
@@ -36,15 +36,13 @@ static int fanotify_merge(struct list_head *list, struct fsnotify_event *event) | |||
36 | 36 | ||
37 | pr_debug("%s: list=%p event=%p\n", __func__, list, event); | 37 | pr_debug("%s: list=%p event=%p\n", __func__, list, event); |
38 | 38 | ||
39 | #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS | ||
40 | /* | 39 | /* |
41 | * Don't merge a permission event with any other event so that we know | 40 | * Don't merge a permission event with any other event so that we know |
42 | * the event structure we have created in fanotify_handle_event() is the | 41 | * the event structure we have created in fanotify_handle_event() is the |
43 | * one we should check for permission response. | 42 | * one we should check for permission response. |
44 | */ | 43 | */ |
45 | if (event->mask & FAN_ALL_PERM_EVENTS) | 44 | if (fanotify_is_perm_event(event->mask)) |
46 | return 0; | 45 | return 0; |
47 | #endif | ||
48 | 46 | ||
49 | list_for_each_entry_reverse(test_event, list, list) { | 47 | list_for_each_entry_reverse(test_event, list, list) { |
50 | if (should_merge(test_event, event)) { | 48 | if (should_merge(test_event, event)) { |
@@ -56,7 +54,6 @@ static int fanotify_merge(struct list_head *list, struct fsnotify_event *event) | |||
56 | return 0; | 54 | return 0; |
57 | } | 55 | } |
58 | 56 | ||
59 | #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS | ||
60 | static int fanotify_get_response(struct fsnotify_group *group, | 57 | static int fanotify_get_response(struct fsnotify_group *group, |
61 | struct fanotify_perm_event_info *event, | 58 | struct fanotify_perm_event_info *event, |
62 | struct fsnotify_iter_info *iter_info) | 59 | struct fsnotify_iter_info *iter_info) |
@@ -65,19 +62,8 @@ static int fanotify_get_response(struct fsnotify_group *group, | |||
65 | 62 | ||
66 | pr_debug("%s: group=%p event=%p\n", __func__, group, event); | 63 | pr_debug("%s: group=%p event=%p\n", __func__, group, event); |
67 | 64 | ||
68 | /* | ||
69 | * fsnotify_prepare_user_wait() fails if we race with mark deletion. | ||
70 | * Just let the operation pass in that case. | ||
71 | */ | ||
72 | if (!fsnotify_prepare_user_wait(iter_info)) { | ||
73 | event->response = FAN_ALLOW; | ||
74 | goto out; | ||
75 | } | ||
76 | |||
77 | wait_event(group->fanotify_data.access_waitq, event->response); | 65 | wait_event(group->fanotify_data.access_waitq, event->response); |
78 | 66 | ||
79 | fsnotify_finish_user_wait(iter_info); | ||
80 | out: | ||
81 | /* userspace responded, convert to something usable */ | 67 | /* userspace responded, convert to something usable */ |
82 | switch (event->response) { | 68 | switch (event->response) { |
83 | case FAN_ALLOW: | 69 | case FAN_ALLOW: |
@@ -94,7 +80,6 @@ out: | |||
94 | 80 | ||
95 | return ret; | 81 | return ret; |
96 | } | 82 | } |
97 | #endif | ||
98 | 83 | ||
99 | static bool fanotify_should_send_event(struct fsnotify_mark *inode_mark, | 84 | static bool fanotify_should_send_event(struct fsnotify_mark *inode_mark, |
100 | struct fsnotify_mark *vfsmnt_mark, | 85 | struct fsnotify_mark *vfsmnt_mark, |
@@ -153,8 +138,7 @@ struct fanotify_event_info *fanotify_alloc_event(struct inode *inode, u32 mask, | |||
153 | { | 138 | { |
154 | struct fanotify_event_info *event; | 139 | struct fanotify_event_info *event; |
155 | 140 | ||
156 | #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS | 141 | if (fanotify_is_perm_event(mask)) { |
157 | if (mask & FAN_ALL_PERM_EVENTS) { | ||
158 | struct fanotify_perm_event_info *pevent; | 142 | struct fanotify_perm_event_info *pevent; |
159 | 143 | ||
160 | pevent = kmem_cache_alloc(fanotify_perm_event_cachep, | 144 | pevent = kmem_cache_alloc(fanotify_perm_event_cachep, |
@@ -165,7 +149,6 @@ struct fanotify_event_info *fanotify_alloc_event(struct inode *inode, u32 mask, | |||
165 | pevent->response = 0; | 149 | pevent->response = 0; |
166 | goto init; | 150 | goto init; |
167 | } | 151 | } |
168 | #endif | ||
169 | event = kmem_cache_alloc(fanotify_event_cachep, GFP_KERNEL); | 152 | event = kmem_cache_alloc(fanotify_event_cachep, GFP_KERNEL); |
170 | if (!event) | 153 | if (!event) |
171 | return NULL; | 154 | return NULL; |
@@ -212,9 +195,19 @@ static int fanotify_handle_event(struct fsnotify_group *group, | |||
212 | pr_debug("%s: group=%p inode=%p mask=%x\n", __func__, group, inode, | 195 | pr_debug("%s: group=%p inode=%p mask=%x\n", __func__, group, inode, |
213 | mask); | 196 | mask); |
214 | 197 | ||
198 | if (fanotify_is_perm_event(mask)) { | ||
199 | /* | ||
200 | * fsnotify_prepare_user_wait() fails if we race with mark | ||
201 | * deletion. Just let the operation pass in that case. | ||
202 | */ | ||
203 | if (!fsnotify_prepare_user_wait(iter_info)) | ||
204 | return 0; | ||
205 | } | ||
206 | |||
215 | event = fanotify_alloc_event(inode, mask, data); | 207 | event = fanotify_alloc_event(inode, mask, data); |
208 | ret = -ENOMEM; | ||
216 | if (unlikely(!event)) | 209 | if (unlikely(!event)) |
217 | return -ENOMEM; | 210 | goto finish; |
218 | 211 | ||
219 | fsn_event = &event->fse; | 212 | fsn_event = &event->fse; |
220 | ret = fsnotify_add_event(group, fsn_event, fanotify_merge); | 213 | ret = fsnotify_add_event(group, fsn_event, fanotify_merge); |
@@ -224,16 +217,16 @@ static int fanotify_handle_event(struct fsnotify_group *group, | |||
224 | /* Our event wasn't used in the end. Free it. */ | 217 | /* Our event wasn't used in the end. Free it. */ |
225 | fsnotify_destroy_event(group, fsn_event); | 218 | fsnotify_destroy_event(group, fsn_event); |
226 | 219 | ||
227 | return 0; | 220 | ret = 0; |
228 | } | 221 | } else if (fanotify_is_perm_event(mask)) { |
229 | |||
230 | #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS | ||
231 | if (mask & FAN_ALL_PERM_EVENTS) { | ||
232 | ret = fanotify_get_response(group, FANOTIFY_PE(fsn_event), | 222 | ret = fanotify_get_response(group, FANOTIFY_PE(fsn_event), |
233 | iter_info); | 223 | iter_info); |
234 | fsnotify_destroy_event(group, fsn_event); | 224 | fsnotify_destroy_event(group, fsn_event); |
235 | } | 225 | } |
236 | #endif | 226 | finish: |
227 | if (fanotify_is_perm_event(mask)) | ||
228 | fsnotify_finish_user_wait(iter_info); | ||
229 | |||
237 | return ret; | 230 | return ret; |
238 | } | 231 | } |
239 | 232 | ||
@@ -253,13 +246,11 @@ static void fanotify_free_event(struct fsnotify_event *fsn_event) | |||
253 | event = FANOTIFY_E(fsn_event); | 246 | event = FANOTIFY_E(fsn_event); |
254 | path_put(&event->path); | 247 | path_put(&event->path); |
255 | put_pid(event->tgid); | 248 | put_pid(event->tgid); |
256 | #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS | 249 | if (fanotify_is_perm_event(fsn_event->mask)) { |
257 | if (fsn_event->mask & FAN_ALL_PERM_EVENTS) { | ||
258 | kmem_cache_free(fanotify_perm_event_cachep, | 250 | kmem_cache_free(fanotify_perm_event_cachep, |
259 | FANOTIFY_PE(fsn_event)); | 251 | FANOTIFY_PE(fsn_event)); |
260 | return; | 252 | return; |
261 | } | 253 | } |
262 | #endif | ||
263 | kmem_cache_free(fanotify_event_cachep, event); | 254 | kmem_cache_free(fanotify_event_cachep, event); |
264 | } | 255 | } |
265 | 256 | ||
diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h index 7dacb7d80727..256d9d1ddea9 100644 --- a/fs/notify/fanotify/fanotify.h +++ b/fs/notify/fanotify/fanotify.h | |||
@@ -22,7 +22,6 @@ struct fanotify_event_info { | |||
22 | struct pid *tgid; | 22 | struct pid *tgid; |
23 | }; | 23 | }; |
24 | 24 | ||
25 | #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS | ||
26 | /* | 25 | /* |
27 | * Structure for permission fanotify events. It gets allocated and freed in | 26 | * Structure for permission fanotify events. It gets allocated and freed in |
28 | * fanotify_handle_event() since we wait there for user response. When the | 27 | * fanotify_handle_event() since we wait there for user response. When the |
@@ -41,7 +40,12 @@ FANOTIFY_PE(struct fsnotify_event *fse) | |||
41 | { | 40 | { |
42 | return container_of(fse, struct fanotify_perm_event_info, fae.fse); | 41 | return container_of(fse, struct fanotify_perm_event_info, fae.fse); |
43 | } | 42 | } |
44 | #endif | 43 | |
44 | static inline bool fanotify_is_perm_event(u32 mask) | ||
45 | { | ||
46 | return IS_ENABLED(CONFIG_FANOTIFY_ACCESS_PERMISSIONS) && | ||
47 | mask & FAN_ALL_PERM_EVENTS; | ||
48 | } | ||
45 | 49 | ||
46 | static inline struct fanotify_event_info *FANOTIFY_E(struct fsnotify_event *fse) | 50 | static inline struct fanotify_event_info *FANOTIFY_E(struct fsnotify_event *fse) |
47 | { | 51 | { |
diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index 9752e7270e61..55499f5a1c96 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c | |||
@@ -143,7 +143,6 @@ static int fill_event_metadata(struct fsnotify_group *group, | |||
143 | return ret; | 143 | return ret; |
144 | } | 144 | } |
145 | 145 | ||
146 | #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS | ||
147 | static struct fanotify_perm_event_info *dequeue_event( | 146 | static struct fanotify_perm_event_info *dequeue_event( |
148 | struct fsnotify_group *group, int fd) | 147 | struct fsnotify_group *group, int fd) |
149 | { | 148 | { |
@@ -200,7 +199,6 @@ static int process_access_response(struct fsnotify_group *group, | |||
200 | 199 | ||
201 | return 0; | 200 | return 0; |
202 | } | 201 | } |
203 | #endif | ||
204 | 202 | ||
205 | static ssize_t copy_event_to_user(struct fsnotify_group *group, | 203 | static ssize_t copy_event_to_user(struct fsnotify_group *group, |
206 | struct fsnotify_event *event, | 204 | struct fsnotify_event *event, |
@@ -222,10 +220,8 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group, | |||
222 | fanotify_event_metadata.event_len)) | 220 | fanotify_event_metadata.event_len)) |
223 | goto out_close_fd; | 221 | goto out_close_fd; |
224 | 222 | ||
225 | #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS | 223 | if (fanotify_is_perm_event(event->mask)) |
226 | if (event->mask & FAN_ALL_PERM_EVENTS) | ||
227 | FANOTIFY_PE(event)->fd = fd; | 224 | FANOTIFY_PE(event)->fd = fd; |
228 | #endif | ||
229 | 225 | ||
230 | if (fd != FAN_NOFD) | 226 | if (fd != FAN_NOFD) |
231 | fd_install(fd, f); | 227 | fd_install(fd, f); |
@@ -310,10 +306,9 @@ static ssize_t fanotify_read(struct file *file, char __user *buf, | |||
310 | * Permission events get queued to wait for response. Other | 306 | * Permission events get queued to wait for response. Other |
311 | * events can be destroyed now. | 307 | * events can be destroyed now. |
312 | */ | 308 | */ |
313 | if (!(kevent->mask & FAN_ALL_PERM_EVENTS)) { | 309 | if (!fanotify_is_perm_event(kevent->mask)) { |
314 | fsnotify_destroy_event(group, kevent); | 310 | fsnotify_destroy_event(group, kevent); |
315 | } else { | 311 | } else { |
316 | #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS | ||
317 | if (ret <= 0) { | 312 | if (ret <= 0) { |
318 | FANOTIFY_PE(kevent)->response = FAN_DENY; | 313 | FANOTIFY_PE(kevent)->response = FAN_DENY; |
319 | wake_up(&group->fanotify_data.access_waitq); | 314 | wake_up(&group->fanotify_data.access_waitq); |
@@ -323,7 +318,6 @@ static ssize_t fanotify_read(struct file *file, char __user *buf, | |||
323 | &group->fanotify_data.access_list); | 318 | &group->fanotify_data.access_list); |
324 | spin_unlock(&group->notification_lock); | 319 | spin_unlock(&group->notification_lock); |
325 | } | 320 | } |
326 | #endif | ||
327 | } | 321 | } |
328 | if (ret < 0) | 322 | if (ret < 0) |
329 | break; | 323 | break; |
@@ -339,11 +333,13 @@ static ssize_t fanotify_read(struct file *file, char __user *buf, | |||
339 | 333 | ||
340 | static ssize_t fanotify_write(struct file *file, const char __user *buf, size_t count, loff_t *pos) | 334 | static ssize_t fanotify_write(struct file *file, const char __user *buf, size_t count, loff_t *pos) |
341 | { | 335 | { |
342 | #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS | ||
343 | struct fanotify_response response = { .fd = -1, .response = -1 }; | 336 | struct fanotify_response response = { .fd = -1, .response = -1 }; |
344 | struct fsnotify_group *group; | 337 | struct fsnotify_group *group; |
345 | int ret; | 338 | int ret; |
346 | 339 | ||
340 | if (!IS_ENABLED(CONFIG_FANOTIFY_ACCESS_PERMISSIONS)) | ||
341 | return -EINVAL; | ||
342 | |||
347 | group = file->private_data; | 343 | group = file->private_data; |
348 | 344 | ||
349 | if (count > sizeof(response)) | 345 | if (count > sizeof(response)) |
@@ -359,16 +355,11 @@ static ssize_t fanotify_write(struct file *file, const char __user *buf, size_t | |||
359 | count = ret; | 355 | count = ret; |
360 | 356 | ||
361 | return count; | 357 | return count; |
362 | #else | ||
363 | return -EINVAL; | ||
364 | #endif | ||
365 | } | 358 | } |
366 | 359 | ||
367 | static int fanotify_release(struct inode *ignored, struct file *file) | 360 | static int fanotify_release(struct inode *ignored, struct file *file) |
368 | { | 361 | { |
369 | struct fsnotify_group *group = file->private_data; | 362 | struct fsnotify_group *group = file->private_data; |
370 | |||
371 | #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS | ||
372 | struct fanotify_perm_event_info *event, *next; | 363 | struct fanotify_perm_event_info *event, *next; |
373 | struct fsnotify_event *fsn_event; | 364 | struct fsnotify_event *fsn_event; |
374 | 365 | ||
@@ -404,14 +395,14 @@ static int fanotify_release(struct inode *ignored, struct file *file) | |||
404 | spin_unlock(&group->notification_lock); | 395 | spin_unlock(&group->notification_lock); |
405 | fsnotify_destroy_event(group, fsn_event); | 396 | fsnotify_destroy_event(group, fsn_event); |
406 | spin_lock(&group->notification_lock); | 397 | spin_lock(&group->notification_lock); |
407 | } else | 398 | } else { |
408 | FANOTIFY_PE(fsn_event)->response = FAN_ALLOW; | 399 | FANOTIFY_PE(fsn_event)->response = FAN_ALLOW; |
400 | } | ||
409 | } | 401 | } |
410 | spin_unlock(&group->notification_lock); | 402 | spin_unlock(&group->notification_lock); |
411 | 403 | ||
412 | /* Response for all permission events it set, wakeup waiters */ | 404 | /* Response for all permission events it set, wakeup waiters */ |
413 | wake_up(&group->fanotify_data.access_waitq); | 405 | wake_up(&group->fanotify_data.access_waitq); |
414 | #endif | ||
415 | 406 | ||
416 | /* matches the fanotify_init->fsnotify_alloc_group */ | 407 | /* matches the fanotify_init->fsnotify_alloc_group */ |
417 | fsnotify_destroy_group(group); | 408 | fsnotify_destroy_group(group); |
@@ -769,10 +760,8 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) | |||
769 | if (force_o_largefile()) | 760 | if (force_o_largefile()) |
770 | event_f_flags |= O_LARGEFILE; | 761 | event_f_flags |= O_LARGEFILE; |
771 | group->fanotify_data.f_flags = event_f_flags; | 762 | group->fanotify_data.f_flags = event_f_flags; |
772 | #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS | ||
773 | init_waitqueue_head(&group->fanotify_data.access_waitq); | 763 | init_waitqueue_head(&group->fanotify_data.access_waitq); |
774 | INIT_LIST_HEAD(&group->fanotify_data.access_list); | 764 | INIT_LIST_HEAD(&group->fanotify_data.access_list); |
775 | #endif | ||
776 | switch (flags & FAN_ALL_CLASS_BITS) { | 765 | switch (flags & FAN_ALL_CLASS_BITS) { |
777 | case FAN_CLASS_NOTIF: | 766 | case FAN_CLASS_NOTIF: |
778 | group->priority = FS_PRIO_0; | 767 | group->priority = FS_PRIO_0; |
@@ -826,6 +815,7 @@ SYSCALL_DEFINE5(fanotify_mark, int, fanotify_fd, unsigned int, flags, | |||
826 | struct fsnotify_group *group; | 815 | struct fsnotify_group *group; |
827 | struct fd f; | 816 | struct fd f; |
828 | struct path path; | 817 | struct path path; |
818 | u32 valid_mask = FAN_ALL_EVENTS | FAN_EVENT_ON_CHILD; | ||
829 | int ret; | 819 | int ret; |
830 | 820 | ||
831 | pr_debug("%s: fanotify_fd=%d flags=%x dfd=%d pathname=%p mask=%llx\n", | 821 | pr_debug("%s: fanotify_fd=%d flags=%x dfd=%d pathname=%p mask=%llx\n", |
@@ -856,11 +846,10 @@ SYSCALL_DEFINE5(fanotify_mark, int, fanotify_fd, unsigned int, flags, | |||
856 | mask &= ~FAN_ONDIR; | 846 | mask &= ~FAN_ONDIR; |
857 | } | 847 | } |
858 | 848 | ||
859 | #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS | 849 | if (IS_ENABLED(CONFIG_FANOTIFY_ACCESS_PERMISSIONS)) |
860 | if (mask & ~(FAN_ALL_EVENTS | FAN_ALL_PERM_EVENTS | FAN_EVENT_ON_CHILD)) | 850 | valid_mask |= FAN_ALL_PERM_EVENTS; |
861 | #else | 851 | |
862 | if (mask & ~(FAN_ALL_EVENTS | FAN_EVENT_ON_CHILD)) | 852 | if (mask & ~valid_mask) |
863 | #endif | ||
864 | return -EINVAL; | 853 | return -EINVAL; |
865 | 854 | ||
866 | f = fdget(fanotify_fd); | 855 | f = fdget(fanotify_fd); |
@@ -950,10 +939,10 @@ static int __init fanotify_user_setup(void) | |||
950 | { | 939 | { |
951 | fanotify_mark_cache = KMEM_CACHE(fsnotify_mark, SLAB_PANIC); | 940 | fanotify_mark_cache = KMEM_CACHE(fsnotify_mark, SLAB_PANIC); |
952 | fanotify_event_cachep = KMEM_CACHE(fanotify_event_info, SLAB_PANIC); | 941 | fanotify_event_cachep = KMEM_CACHE(fanotify_event_info, SLAB_PANIC); |
953 | #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS | 942 | if (IS_ENABLED(CONFIG_FANOTIFY_ACCESS_PERMISSIONS)) { |
954 | fanotify_perm_event_cachep = KMEM_CACHE(fanotify_perm_event_info, | 943 | fanotify_perm_event_cachep = |
955 | SLAB_PANIC); | 944 | KMEM_CACHE(fanotify_perm_event_info, SLAB_PANIC); |
956 | #endif | 945 | } |
957 | 946 | ||
958 | return 0; | 947 | return 0; |
959 | } | 948 | } |
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index 0c4583b61717..81d8959b6aef 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c | |||
@@ -243,6 +243,29 @@ static int send_to_group(struct inode *to_tell, | |||
243 | file_name, cookie, iter_info); | 243 | file_name, cookie, iter_info); |
244 | } | 244 | } |
245 | 245 | ||
246 | static struct fsnotify_mark *fsnotify_first_mark(struct fsnotify_mark_connector **connp) | ||
247 | { | ||
248 | struct fsnotify_mark_connector *conn; | ||
249 | struct hlist_node *node = NULL; | ||
250 | |||
251 | conn = srcu_dereference(*connp, &fsnotify_mark_srcu); | ||
252 | if (conn) | ||
253 | node = srcu_dereference(conn->list.first, &fsnotify_mark_srcu); | ||
254 | |||
255 | return hlist_entry_safe(node, struct fsnotify_mark, obj_list); | ||
256 | } | ||
257 | |||
258 | static struct fsnotify_mark *fsnotify_next_mark(struct fsnotify_mark *mark) | ||
259 | { | ||
260 | struct hlist_node *node = NULL; | ||
261 | |||
262 | if (mark) | ||
263 | node = srcu_dereference(mark->obj_list.next, | ||
264 | &fsnotify_mark_srcu); | ||
265 | |||
266 | return hlist_entry_safe(node, struct fsnotify_mark, obj_list); | ||
267 | } | ||
268 | |||
246 | /* | 269 | /* |
247 | * This is the main call to fsnotify. The VFS calls into hook specific functions | 270 | * This is the main call to fsnotify. The VFS calls into hook specific functions |
248 | * in linux/fsnotify.h. Those functions then in turn call here. Here will call | 271 | * in linux/fsnotify.h. Those functions then in turn call here. Here will call |
@@ -252,11 +275,7 @@ static int send_to_group(struct inode *to_tell, | |||
252 | int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_is, | 275 | int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_is, |
253 | const unsigned char *file_name, u32 cookie) | 276 | const unsigned char *file_name, u32 cookie) |
254 | { | 277 | { |
255 | struct hlist_node *inode_node = NULL, *vfsmount_node = NULL; | 278 | struct fsnotify_iter_info iter_info = {}; |
256 | struct fsnotify_mark *inode_mark = NULL, *vfsmount_mark = NULL; | ||
257 | struct fsnotify_group *inode_group, *vfsmount_group; | ||
258 | struct fsnotify_mark_connector *inode_conn, *vfsmount_conn; | ||
259 | struct fsnotify_iter_info iter_info; | ||
260 | struct mount *mnt; | 279 | struct mount *mnt; |
261 | int ret = 0; | 280 | int ret = 0; |
262 | /* global tests shouldn't care about events on child only the specific event */ | 281 | /* global tests shouldn't care about events on child only the specific event */ |
@@ -291,26 +310,16 @@ int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_is, | |||
291 | 310 | ||
292 | if ((mask & FS_MODIFY) || | 311 | if ((mask & FS_MODIFY) || |
293 | (test_mask & to_tell->i_fsnotify_mask)) { | 312 | (test_mask & to_tell->i_fsnotify_mask)) { |
294 | inode_conn = srcu_dereference(to_tell->i_fsnotify_marks, | 313 | iter_info.inode_mark = |
295 | &fsnotify_mark_srcu); | 314 | fsnotify_first_mark(&to_tell->i_fsnotify_marks); |
296 | if (inode_conn) | ||
297 | inode_node = srcu_dereference(inode_conn->list.first, | ||
298 | &fsnotify_mark_srcu); | ||
299 | } | 315 | } |
300 | 316 | ||
301 | if (mnt && ((mask & FS_MODIFY) || | 317 | if (mnt && ((mask & FS_MODIFY) || |
302 | (test_mask & mnt->mnt_fsnotify_mask))) { | 318 | (test_mask & mnt->mnt_fsnotify_mask))) { |
303 | inode_conn = srcu_dereference(to_tell->i_fsnotify_marks, | 319 | iter_info.inode_mark = |
304 | &fsnotify_mark_srcu); | 320 | fsnotify_first_mark(&to_tell->i_fsnotify_marks); |
305 | if (inode_conn) | 321 | iter_info.vfsmount_mark = |
306 | inode_node = srcu_dereference(inode_conn->list.first, | 322 | fsnotify_first_mark(&mnt->mnt_fsnotify_marks); |
307 | &fsnotify_mark_srcu); | ||
308 | vfsmount_conn = srcu_dereference(mnt->mnt_fsnotify_marks, | ||
309 | &fsnotify_mark_srcu); | ||
310 | if (vfsmount_conn) | ||
311 | vfsmount_node = srcu_dereference( | ||
312 | vfsmount_conn->list.first, | ||
313 | &fsnotify_mark_srcu); | ||
314 | } | 323 | } |
315 | 324 | ||
316 | /* | 325 | /* |
@@ -318,39 +327,19 @@ int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_is, | |||
318 | * ignore masks are properly reflected for mount mark notifications. | 327 | * ignore masks are properly reflected for mount mark notifications. |
319 | * That's why this traversal is so complicated... | 328 | * That's why this traversal is so complicated... |
320 | */ | 329 | */ |
321 | while (inode_node || vfsmount_node) { | 330 | while (iter_info.inode_mark || iter_info.vfsmount_mark) { |
322 | inode_group = NULL; | 331 | struct fsnotify_mark *inode_mark = iter_info.inode_mark; |
323 | inode_mark = NULL; | 332 | struct fsnotify_mark *vfsmount_mark = iter_info.vfsmount_mark; |
324 | vfsmount_group = NULL; | 333 | |
325 | vfsmount_mark = NULL; | 334 | if (inode_mark && vfsmount_mark) { |
326 | 335 | int cmp = fsnotify_compare_groups(inode_mark->group, | |
327 | if (inode_node) { | 336 | vfsmount_mark->group); |
328 | inode_mark = hlist_entry(srcu_dereference(inode_node, &fsnotify_mark_srcu), | 337 | if (cmp > 0) |
329 | struct fsnotify_mark, obj_list); | ||
330 | inode_group = inode_mark->group; | ||
331 | } | ||
332 | |||
333 | if (vfsmount_node) { | ||
334 | vfsmount_mark = hlist_entry(srcu_dereference(vfsmount_node, &fsnotify_mark_srcu), | ||
335 | struct fsnotify_mark, obj_list); | ||
336 | vfsmount_group = vfsmount_mark->group; | ||
337 | } | ||
338 | |||
339 | if (inode_group && vfsmount_group) { | ||
340 | int cmp = fsnotify_compare_groups(inode_group, | ||
341 | vfsmount_group); | ||
342 | if (cmp > 0) { | ||
343 | inode_group = NULL; | ||
344 | inode_mark = NULL; | 338 | inode_mark = NULL; |
345 | } else if (cmp < 0) { | 339 | else if (cmp < 0) |
346 | vfsmount_group = NULL; | ||
347 | vfsmount_mark = NULL; | 340 | vfsmount_mark = NULL; |
348 | } | ||
349 | } | 341 | } |
350 | 342 | ||
351 | iter_info.inode_mark = inode_mark; | ||
352 | iter_info.vfsmount_mark = vfsmount_mark; | ||
353 | |||
354 | ret = send_to_group(to_tell, inode_mark, vfsmount_mark, mask, | 343 | ret = send_to_group(to_tell, inode_mark, vfsmount_mark, mask, |
355 | data, data_is, cookie, file_name, | 344 | data, data_is, cookie, file_name, |
356 | &iter_info); | 345 | &iter_info); |
@@ -358,12 +347,12 @@ int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_is, | |||
358 | if (ret && (mask & ALL_FSNOTIFY_PERM_EVENTS)) | 347 | if (ret && (mask & ALL_FSNOTIFY_PERM_EVENTS)) |
359 | goto out; | 348 | goto out; |
360 | 349 | ||
361 | if (inode_group) | 350 | if (inode_mark) |
362 | inode_node = srcu_dereference(inode_node->next, | 351 | iter_info.inode_mark = |
363 | &fsnotify_mark_srcu); | 352 | fsnotify_next_mark(iter_info.inode_mark); |
364 | if (vfsmount_group) | 353 | if (vfsmount_mark) |
365 | vfsmount_node = srcu_dereference(vfsmount_node->next, | 354 | iter_info.vfsmount_mark = |
366 | &fsnotify_mark_srcu); | 355 | fsnotify_next_mark(iter_info.vfsmount_mark); |
367 | } | 356 | } |
368 | ret = 0; | 357 | ret = 0; |
369 | out: | 358 | out: |
diff --git a/fs/notify/group.c b/fs/notify/group.c index 32357534de18..b7a4b6a69efa 100644 --- a/fs/notify/group.c +++ b/fs/notify/group.c | |||
@@ -107,7 +107,7 @@ void fsnotify_destroy_group(struct fsnotify_group *group) | |||
107 | */ | 107 | */ |
108 | void fsnotify_get_group(struct fsnotify_group *group) | 108 | void fsnotify_get_group(struct fsnotify_group *group) |
109 | { | 109 | { |
110 | atomic_inc(&group->refcnt); | 110 | refcount_inc(&group->refcnt); |
111 | } | 111 | } |
112 | 112 | ||
113 | /* | 113 | /* |
@@ -115,7 +115,7 @@ void fsnotify_get_group(struct fsnotify_group *group) | |||
115 | */ | 115 | */ |
116 | void fsnotify_put_group(struct fsnotify_group *group) | 116 | void fsnotify_put_group(struct fsnotify_group *group) |
117 | { | 117 | { |
118 | if (atomic_dec_and_test(&group->refcnt)) | 118 | if (refcount_dec_and_test(&group->refcnt)) |
119 | fsnotify_final_destroy_group(group); | 119 | fsnotify_final_destroy_group(group); |
120 | } | 120 | } |
121 | 121 | ||
@@ -131,7 +131,7 @@ struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops) | |||
131 | return ERR_PTR(-ENOMEM); | 131 | return ERR_PTR(-ENOMEM); |
132 | 132 | ||
133 | /* set to 0 when there a no external references to this group */ | 133 | /* set to 0 when there a no external references to this group */ |
134 | atomic_set(&group->refcnt, 1); | 134 | refcount_set(&group->refcnt, 1); |
135 | atomic_set(&group->num_marks, 0); | 135 | atomic_set(&group->num_marks, 0); |
136 | atomic_set(&group->user_waits, 0); | 136 | atomic_set(&group->user_waits, 0); |
137 | 137 | ||
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c index 7cc7d3fb1862..d3c20e0bb046 100644 --- a/fs/notify/inotify/inotify_user.c +++ b/fs/notify/inotify/inotify_user.c | |||
@@ -376,7 +376,7 @@ static struct inotify_inode_mark *inotify_idr_find_locked(struct fsnotify_group | |||
376 | 376 | ||
377 | fsnotify_get_mark(fsn_mark); | 377 | fsnotify_get_mark(fsn_mark); |
378 | /* One ref for being in the idr, one ref we just took */ | 378 | /* One ref for being in the idr, one ref we just took */ |
379 | BUG_ON(atomic_read(&fsn_mark->refcnt) < 2); | 379 | BUG_ON(refcount_read(&fsn_mark->refcnt) < 2); |
380 | } | 380 | } |
381 | 381 | ||
382 | return i_mark; | 382 | return i_mark; |
@@ -446,7 +446,7 @@ static void inotify_remove_from_idr(struct fsnotify_group *group, | |||
446 | * One ref for being in the idr | 446 | * One ref for being in the idr |
447 | * one ref grabbed by inotify_idr_find | 447 | * one ref grabbed by inotify_idr_find |
448 | */ | 448 | */ |
449 | if (unlikely(atomic_read(&i_mark->fsn_mark.refcnt) < 2)) { | 449 | if (unlikely(refcount_read(&i_mark->fsn_mark.refcnt) < 2)) { |
450 | printk(KERN_ERR "%s: i_mark=%p i_mark->wd=%d i_mark->group=%p\n", | 450 | printk(KERN_ERR "%s: i_mark=%p i_mark->wd=%d i_mark->group=%p\n", |
451 | __func__, i_mark, i_mark->wd, i_mark->fsn_mark.group); | 451 | __func__, i_mark, i_mark->wd, i_mark->fsn_mark.group); |
452 | /* we can't really recover with bad ref cnting.. */ | 452 | /* we can't really recover with bad ref cnting.. */ |
diff --git a/fs/notify/mark.c b/fs/notify/mark.c index 9991f8826734..e9191b416434 100644 --- a/fs/notify/mark.c +++ b/fs/notify/mark.c | |||
@@ -105,18 +105,8 @@ static DECLARE_WORK(connector_reaper_work, fsnotify_connector_destroy_workfn); | |||
105 | 105 | ||
106 | void fsnotify_get_mark(struct fsnotify_mark *mark) | 106 | void fsnotify_get_mark(struct fsnotify_mark *mark) |
107 | { | 107 | { |
108 | WARN_ON_ONCE(!atomic_read(&mark->refcnt)); | 108 | WARN_ON_ONCE(!refcount_read(&mark->refcnt)); |
109 | atomic_inc(&mark->refcnt); | 109 | refcount_inc(&mark->refcnt); |
110 | } | ||
111 | |||
112 | /* | ||
113 | * Get mark reference when we found the mark via lockless traversal of object | ||
114 | * list. Mark can be already removed from the list by now and on its way to be | ||
115 | * destroyed once SRCU period ends. | ||
116 | */ | ||
117 | static bool fsnotify_get_mark_safe(struct fsnotify_mark *mark) | ||
118 | { | ||
119 | return atomic_inc_not_zero(&mark->refcnt); | ||
120 | } | 110 | } |
121 | 111 | ||
122 | static void __fsnotify_recalc_mask(struct fsnotify_mark_connector *conn) | 112 | static void __fsnotify_recalc_mask(struct fsnotify_mark_connector *conn) |
@@ -211,7 +201,7 @@ void fsnotify_put_mark(struct fsnotify_mark *mark) | |||
211 | 201 | ||
212 | /* Catch marks that were actually never attached to object */ | 202 | /* Catch marks that were actually never attached to object */ |
213 | if (!mark->connector) { | 203 | if (!mark->connector) { |
214 | if (atomic_dec_and_test(&mark->refcnt)) | 204 | if (refcount_dec_and_test(&mark->refcnt)) |
215 | fsnotify_final_mark_destroy(mark); | 205 | fsnotify_final_mark_destroy(mark); |
216 | return; | 206 | return; |
217 | } | 207 | } |
@@ -220,7 +210,7 @@ void fsnotify_put_mark(struct fsnotify_mark *mark) | |||
220 | * We have to be careful so that traversals of obj_list under lock can | 210 | * We have to be careful so that traversals of obj_list under lock can |
221 | * safely grab mark reference. | 211 | * safely grab mark reference. |
222 | */ | 212 | */ |
223 | if (!atomic_dec_and_lock(&mark->refcnt, &mark->connector->lock)) | 213 | if (!refcount_dec_and_lock(&mark->refcnt, &mark->connector->lock)) |
224 | return; | 214 | return; |
225 | 215 | ||
226 | conn = mark->connector; | 216 | conn = mark->connector; |
@@ -256,32 +246,60 @@ void fsnotify_put_mark(struct fsnotify_mark *mark) | |||
256 | FSNOTIFY_REAPER_DELAY); | 246 | FSNOTIFY_REAPER_DELAY); |
257 | } | 247 | } |
258 | 248 | ||
259 | bool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info) | 249 | /* |
250 | * Get mark reference when we found the mark via lockless traversal of object | ||
251 | * list. Mark can be already removed from the list by now and on its way to be | ||
252 | * destroyed once SRCU period ends. | ||
253 | * | ||
254 | * Also pin the group so it doesn't disappear under us. | ||
255 | */ | ||
256 | static bool fsnotify_get_mark_safe(struct fsnotify_mark *mark) | ||
260 | { | 257 | { |
261 | struct fsnotify_group *group; | 258 | if (!mark) |
262 | 259 | return true; | |
263 | if (WARN_ON_ONCE(!iter_info->inode_mark && !iter_info->vfsmount_mark)) | 260 | |
264 | return false; | 261 | if (refcount_inc_not_zero(&mark->refcnt)) { |
265 | 262 | spin_lock(&mark->lock); | |
266 | if (iter_info->inode_mark) | 263 | if (mark->flags & FSNOTIFY_MARK_FLAG_ATTACHED) { |
267 | group = iter_info->inode_mark->group; | 264 | /* mark is attached, group is still alive then */ |
268 | else | 265 | atomic_inc(&mark->group->user_waits); |
269 | group = iter_info->vfsmount_mark->group; | 266 | spin_unlock(&mark->lock); |
267 | return true; | ||
268 | } | ||
269 | spin_unlock(&mark->lock); | ||
270 | fsnotify_put_mark(mark); | ||
271 | } | ||
272 | return false; | ||
273 | } | ||
270 | 274 | ||
271 | /* | 275 | /* |
272 | * Since acquisition of mark reference is an atomic op as well, we can | 276 | * Puts marks and wakes up group destruction if necessary. |
273 | * be sure this inc is seen before any effect of refcount increment. | 277 | * |
274 | */ | 278 | * Pairs with fsnotify_get_mark_safe() |
275 | atomic_inc(&group->user_waits); | 279 | */ |
280 | static void fsnotify_put_mark_wake(struct fsnotify_mark *mark) | ||
281 | { | ||
282 | if (mark) { | ||
283 | struct fsnotify_group *group = mark->group; | ||
276 | 284 | ||
277 | if (iter_info->inode_mark) { | 285 | fsnotify_put_mark(mark); |
278 | /* This can fail if mark is being removed */ | 286 | /* |
279 | if (!fsnotify_get_mark_safe(iter_info->inode_mark)) | 287 | * We abuse notification_waitq on group shutdown for waiting for |
280 | goto out_wait; | 288 | * all marks pinned when waiting for userspace. |
289 | */ | ||
290 | if (atomic_dec_and_test(&group->user_waits) && group->shutdown) | ||
291 | wake_up(&group->notification_waitq); | ||
281 | } | 292 | } |
282 | if (iter_info->vfsmount_mark) { | 293 | } |
283 | if (!fsnotify_get_mark_safe(iter_info->vfsmount_mark)) | 294 | |
284 | goto out_inode; | 295 | bool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info) |
296 | { | ||
297 | /* This can fail if mark is being removed */ | ||
298 | if (!fsnotify_get_mark_safe(iter_info->inode_mark)) | ||
299 | return false; | ||
300 | if (!fsnotify_get_mark_safe(iter_info->vfsmount_mark)) { | ||
301 | fsnotify_put_mark_wake(iter_info->inode_mark); | ||
302 | return false; | ||
285 | } | 303 | } |
286 | 304 | ||
287 | /* | 305 | /* |
@@ -292,34 +310,13 @@ bool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info) | |||
292 | srcu_read_unlock(&fsnotify_mark_srcu, iter_info->srcu_idx); | 310 | srcu_read_unlock(&fsnotify_mark_srcu, iter_info->srcu_idx); |
293 | 311 | ||
294 | return true; | 312 | return true; |
295 | out_inode: | ||
296 | if (iter_info->inode_mark) | ||
297 | fsnotify_put_mark(iter_info->inode_mark); | ||
298 | out_wait: | ||
299 | if (atomic_dec_and_test(&group->user_waits) && group->shutdown) | ||
300 | wake_up(&group->notification_waitq); | ||
301 | return false; | ||
302 | } | 313 | } |
303 | 314 | ||
304 | void fsnotify_finish_user_wait(struct fsnotify_iter_info *iter_info) | 315 | void fsnotify_finish_user_wait(struct fsnotify_iter_info *iter_info) |
305 | { | 316 | { |
306 | struct fsnotify_group *group = NULL; | ||
307 | |||
308 | iter_info->srcu_idx = srcu_read_lock(&fsnotify_mark_srcu); | 317 | iter_info->srcu_idx = srcu_read_lock(&fsnotify_mark_srcu); |
309 | if (iter_info->inode_mark) { | 318 | fsnotify_put_mark_wake(iter_info->inode_mark); |
310 | group = iter_info->inode_mark->group; | 319 | fsnotify_put_mark_wake(iter_info->vfsmount_mark); |
311 | fsnotify_put_mark(iter_info->inode_mark); | ||
312 | } | ||
313 | if (iter_info->vfsmount_mark) { | ||
314 | group = iter_info->vfsmount_mark->group; | ||
315 | fsnotify_put_mark(iter_info->vfsmount_mark); | ||
316 | } | ||
317 | /* | ||
318 | * We abuse notification_waitq on group shutdown for waiting for all | ||
319 | * marks pinned when waiting for userspace. | ||
320 | */ | ||
321 | if (atomic_dec_and_test(&group->user_waits) && group->shutdown) | ||
322 | wake_up(&group->notification_waitq); | ||
323 | } | 320 | } |
324 | 321 | ||
325 | /* | 322 | /* |
@@ -338,7 +335,7 @@ void fsnotify_detach_mark(struct fsnotify_mark *mark) | |||
338 | 335 | ||
339 | WARN_ON_ONCE(!mutex_is_locked(&group->mark_mutex)); | 336 | WARN_ON_ONCE(!mutex_is_locked(&group->mark_mutex)); |
340 | WARN_ON_ONCE(!srcu_read_lock_held(&fsnotify_mark_srcu) && | 337 | WARN_ON_ONCE(!srcu_read_lock_held(&fsnotify_mark_srcu) && |
341 | atomic_read(&mark->refcnt) < 1 + | 338 | refcount_read(&mark->refcnt) < 1 + |
342 | !!(mark->flags & FSNOTIFY_MARK_FLAG_ATTACHED)); | 339 | !!(mark->flags & FSNOTIFY_MARK_FLAG_ATTACHED)); |
343 | 340 | ||
344 | spin_lock(&mark->lock); | 341 | spin_lock(&mark->lock); |
@@ -599,9 +596,11 @@ int fsnotify_add_mark_locked(struct fsnotify_mark *mark, struct inode *inode, | |||
599 | 596 | ||
600 | return ret; | 597 | return ret; |
601 | err: | 598 | err: |
599 | spin_lock(&mark->lock); | ||
602 | mark->flags &= ~(FSNOTIFY_MARK_FLAG_ALIVE | | 600 | mark->flags &= ~(FSNOTIFY_MARK_FLAG_ALIVE | |
603 | FSNOTIFY_MARK_FLAG_ATTACHED); | 601 | FSNOTIFY_MARK_FLAG_ATTACHED); |
604 | list_del_init(&mark->g_list); | 602 | list_del_init(&mark->g_list); |
603 | spin_unlock(&mark->lock); | ||
605 | atomic_dec(&group->num_marks); | 604 | atomic_dec(&group->num_marks); |
606 | 605 | ||
607 | fsnotify_put_mark(mark); | 606 | fsnotify_put_mark(mark); |
@@ -738,7 +737,7 @@ void fsnotify_init_mark(struct fsnotify_mark *mark, | |||
738 | { | 737 | { |
739 | memset(mark, 0, sizeof(*mark)); | 738 | memset(mark, 0, sizeof(*mark)); |
740 | spin_lock_init(&mark->lock); | 739 | spin_lock_init(&mark->lock); |
741 | atomic_set(&mark->refcnt, 1); | 740 | refcount_set(&mark->refcnt, 1); |
742 | fsnotify_get_group(group); | 741 | fsnotify_get_group(group); |
743 | mark->group = group; | 742 | mark->group = group; |
744 | } | 743 | } |