aboutsummaryrefslogtreecommitdiffstats
path: root/fs/notify
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2014-04-03 17:46:33 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-04-03 19:20:51 -0400
commitf083441ba86acb9e2ef9c1d1747725e488c8b1ff (patch)
tree227d46ea995a81645b0a1eb9b5147397a1e0de87 /fs/notify
parent3298cf37bee59c66a51da0cea8bae0d0418e27fd (diff)
fanotify: use fanotify event structure for permission response processing
Currently, fanotify creates new structure to track the fact that permission event has been reported to userspace and someone is waiting for a response to it. As event structures are now completely in the hands of each notification framework, we can use the event structure for this tracking instead of allocating a new structure. Since this makes the event structures for normal events and permission events even more different and the structures have different lifetime rules, we split them into two separate structures (where permission event structure contains the structure for a normal event). This makes normal events 8 bytes smaller and the code a tad bit cleaner. [akpm@linux-foundation.org: fix build] Signed-off-by: Jan Kara <jack@suse.cz> Cc: Eric Paris <eparis@redhat.com> Cc: Al Viro <viro@zeniv.linux.org.uk> Cc: Wu Fengguang <fengguang.wu@intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/notify')
-rw-r--r--fs/notify/fanotify/fanotify.c63
-rw-r--r--fs/notify/fanotify/fanotify.h34
-rw-r--r--fs/notify/fanotify/fanotify_user.c123
3 files changed, 116 insertions, 104 deletions
diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c
index dc638f786d5c..ee9cb3795c2b 100644
--- a/fs/notify/fanotify/fanotify.c
+++ b/fs/notify/fanotify/fanotify.c
@@ -60,8 +60,8 @@ static int fanotify_merge(struct list_head *list, struct fsnotify_event *event)
60} 60}
61 61
62#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS 62#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
63static int fanotify_get_response_from_access(struct fsnotify_group *group, 63static int fanotify_get_response(struct fsnotify_group *group,
64 struct fanotify_event_info *event) 64 struct fanotify_perm_event_info *event)
65{ 65{
66 int ret; 66 int ret;
67 67
@@ -142,6 +142,40 @@ static bool fanotify_should_send_event(struct fsnotify_mark *inode_mark,
142 return false; 142 return false;
143} 143}
144 144
145struct fanotify_event_info *fanotify_alloc_event(struct inode *inode, u32 mask,
146 struct path *path)
147{
148 struct fanotify_event_info *event;
149
150#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
151 if (mask & FAN_ALL_PERM_EVENTS) {
152 struct fanotify_perm_event_info *pevent;
153
154 pevent = kmem_cache_alloc(fanotify_perm_event_cachep,
155 GFP_KERNEL);
156 if (!pevent)
157 return NULL;
158 event = &pevent->fae;
159 pevent->response = 0;
160 goto init;
161 }
162#endif
163 event = kmem_cache_alloc(fanotify_event_cachep, GFP_KERNEL);
164 if (!event)
165 return NULL;
166init: __maybe_unused
167 fsnotify_init_event(&event->fse, inode, mask);
168 event->tgid = get_pid(task_tgid(current));
169 if (path) {
170 event->path = *path;
171 path_get(&event->path);
172 } else {
173 event->path.mnt = NULL;
174 event->path.dentry = NULL;
175 }
176 return event;
177}
178
145static int fanotify_handle_event(struct fsnotify_group *group, 179static int fanotify_handle_event(struct fsnotify_group *group,
146 struct inode *inode, 180 struct inode *inode,
147 struct fsnotify_mark *inode_mark, 181 struct fsnotify_mark *inode_mark,
@@ -171,25 +205,11 @@ static int fanotify_handle_event(struct fsnotify_group *group,
171 pr_debug("%s: group=%p inode=%p mask=%x\n", __func__, group, inode, 205 pr_debug("%s: group=%p inode=%p mask=%x\n", __func__, group, inode,
172 mask); 206 mask);
173 207
174 event = kmem_cache_alloc(fanotify_event_cachep, GFP_KERNEL); 208 event = fanotify_alloc_event(inode, mask, data);
175 if (unlikely(!event)) 209 if (unlikely(!event))
176 return -ENOMEM; 210 return -ENOMEM;
177 211
178 fsn_event = &event->fse; 212 fsn_event = &event->fse;
179 fsnotify_init_event(fsn_event, inode, mask);
180 event->tgid = get_pid(task_tgid(current));
181 if (data_type == FSNOTIFY_EVENT_PATH) {
182 struct path *path = data;
183 event->path = *path;
184 path_get(&event->path);
185 } else {
186 event->path.mnt = NULL;
187 event->path.dentry = NULL;
188 }
189#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
190 event->response = 0;
191#endif
192
193 ret = fsnotify_add_notify_event(group, fsn_event, fanotify_merge); 213 ret = fsnotify_add_notify_event(group, fsn_event, fanotify_merge);
194 if (ret) { 214 if (ret) {
195 /* Permission events shouldn't be merged */ 215 /* Permission events shouldn't be merged */
@@ -202,7 +222,7 @@ static int fanotify_handle_event(struct fsnotify_group *group,
202 222
203#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS 223#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
204 if (mask & FAN_ALL_PERM_EVENTS) { 224 if (mask & FAN_ALL_PERM_EVENTS) {
205 ret = fanotify_get_response_from_access(group, event); 225 ret = fanotify_get_response(group, FANOTIFY_PE(fsn_event));
206 fsnotify_destroy_event(group, fsn_event); 226 fsnotify_destroy_event(group, fsn_event);
207 } 227 }
208#endif 228#endif
@@ -225,6 +245,13 @@ static void fanotify_free_event(struct fsnotify_event *fsn_event)
225 event = FANOTIFY_E(fsn_event); 245 event = FANOTIFY_E(fsn_event);
226 path_put(&event->path); 246 path_put(&event->path);
227 put_pid(event->tgid); 247 put_pid(event->tgid);
248#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
249 if (fsn_event->mask & FAN_ALL_PERM_EVENTS) {
250 kmem_cache_free(fanotify_perm_event_cachep,
251 FANOTIFY_PE(fsn_event));
252 return;
253 }
254#endif
228 kmem_cache_free(fanotify_event_cachep, event); 255 kmem_cache_free(fanotify_event_cachep, event);
229} 256}
230 257
diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h
index 32a2f034fb94..2a5fb14115df 100644
--- a/fs/notify/fanotify/fanotify.h
+++ b/fs/notify/fanotify/fanotify.h
@@ -3,13 +3,12 @@
3#include <linux/slab.h> 3#include <linux/slab.h>
4 4
5extern struct kmem_cache *fanotify_event_cachep; 5extern struct kmem_cache *fanotify_event_cachep;
6extern struct kmem_cache *fanotify_perm_event_cachep;
6 7
7/* 8/*
8 * Lifetime of the structure differs for normal and permission events. In both 9 * Structure for normal fanotify events. It gets allocated in
9 * cases the structure is allocated in fanotify_handle_event(). For normal 10 * fanotify_handle_event() and freed when the information is retrieved by
10 * events the structure is freed immediately after reporting it to userspace. 11 * userspace
11 * For permission events we free it only after we receive response from
12 * userspace.
13 */ 12 */
14struct fanotify_event_info { 13struct fanotify_event_info {
15 struct fsnotify_event fse; 14 struct fsnotify_event fse;
@@ -19,12 +18,33 @@ struct fanotify_event_info {
19 */ 18 */
20 struct path path; 19 struct path path;
21 struct pid *tgid; 20 struct pid *tgid;
21};
22
22#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS 23#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
23 u32 response; /* userspace answer to question */ 24/*
24#endif 25 * Structure for permission fanotify events. It gets allocated and freed in
26 * fanotify_handle_event() since we wait there for user response. When the
27 * information is retrieved by userspace the structure is moved from
28 * group->notification_list to group->fanotify_data.access_list to wait for
29 * user response.
30 */
31struct fanotify_perm_event_info {
32 struct fanotify_event_info fae;
33 int response; /* userspace answer to question */
34 int fd; /* fd we passed to userspace for this event */
25}; 35};
26 36
37static inline struct fanotify_perm_event_info *
38FANOTIFY_PE(struct fsnotify_event *fse)
39{
40 return container_of(fse, struct fanotify_perm_event_info, fae.fse);
41}
42#endif
43
27static inline struct fanotify_event_info *FANOTIFY_E(struct fsnotify_event *fse) 44static inline struct fanotify_event_info *FANOTIFY_E(struct fsnotify_event *fse)
28{ 45{
29 return container_of(fse, struct fanotify_event_info, fse); 46 return container_of(fse, struct fanotify_event_info, fse);
30} 47}
48
49struct fanotify_event_info *fanotify_alloc_event(struct inode *inode, u32 mask,
50 struct path *path);
diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c
index 70fe65437d21..8f5e85269110 100644
--- a/fs/notify/fanotify/fanotify_user.c
+++ b/fs/notify/fanotify/fanotify_user.c
@@ -28,14 +28,8 @@
28extern const struct fsnotify_ops fanotify_fsnotify_ops; 28extern const struct fsnotify_ops fanotify_fsnotify_ops;
29 29
30static struct kmem_cache *fanotify_mark_cache __read_mostly; 30static struct kmem_cache *fanotify_mark_cache __read_mostly;
31static struct kmem_cache *fanotify_response_event_cache __read_mostly;
32struct kmem_cache *fanotify_event_cachep __read_mostly; 31struct kmem_cache *fanotify_event_cachep __read_mostly;
33 32struct kmem_cache *fanotify_perm_event_cachep __read_mostly;
34struct fanotify_response_event {
35 struct list_head list;
36 __s32 fd;
37 struct fanotify_event_info *event;
38};
39 33
40/* 34/*
41 * Get an fsnotify notification event if one exists and is small 35 * Get an fsnotify notification event if one exists and is small
@@ -135,33 +129,34 @@ static int fill_event_metadata(struct fsnotify_group *group,
135} 129}
136 130
137#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS 131#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
138static struct fanotify_response_event *dequeue_re(struct fsnotify_group *group, 132static struct fanotify_perm_event_info *dequeue_event(
139 __s32 fd) 133 struct fsnotify_group *group, int fd)
140{ 134{
141 struct fanotify_response_event *re, *return_re = NULL; 135 struct fanotify_perm_event_info *event, *return_e = NULL;
142 136
143 mutex_lock(&group->fanotify_data.access_mutex); 137 mutex_lock(&group->fanotify_data.access_mutex);
144 list_for_each_entry(re, &group->fanotify_data.access_list, list) { 138 list_for_each_entry(event, &group->fanotify_data.access_list,
145 if (re->fd != fd) 139 fae.fse.list) {
140 if (event->fd != fd)
146 continue; 141 continue;
147 142
148 list_del_init(&re->list); 143 list_del_init(&event->fae.fse.list);
149 return_re = re; 144 return_e = event;
150 break; 145 break;
151 } 146 }
152 mutex_unlock(&group->fanotify_data.access_mutex); 147 mutex_unlock(&group->fanotify_data.access_mutex);
153 148
154 pr_debug("%s: found return_re=%p\n", __func__, return_re); 149 pr_debug("%s: found return_re=%p\n", __func__, return_e);
155 150
156 return return_re; 151 return return_e;
157} 152}
158 153
159static int process_access_response(struct fsnotify_group *group, 154static int process_access_response(struct fsnotify_group *group,
160 struct fanotify_response *response_struct) 155 struct fanotify_response *response_struct)
161{ 156{
162 struct fanotify_response_event *re; 157 struct fanotify_perm_event_info *event;
163 __s32 fd = response_struct->fd; 158 int fd = response_struct->fd;
164 __u32 response = response_struct->response; 159 int response = response_struct->response;
165 160
166 pr_debug("%s: group=%p fd=%d response=%d\n", __func__, group, 161 pr_debug("%s: group=%p fd=%d response=%d\n", __func__, group,
167 fd, response); 162 fd, response);
@@ -181,50 +176,15 @@ static int process_access_response(struct fsnotify_group *group,
181 if (fd < 0) 176 if (fd < 0)
182 return -EINVAL; 177 return -EINVAL;
183 178
184 re = dequeue_re(group, fd); 179 event = dequeue_event(group, fd);
185 if (!re) 180 if (!event)
186 return -ENOENT; 181 return -ENOENT;
187 182
188 re->event->response = response; 183 event->response = response;
189
190 wake_up(&group->fanotify_data.access_waitq); 184 wake_up(&group->fanotify_data.access_waitq);
191 185
192 kmem_cache_free(fanotify_response_event_cache, re);
193
194 return 0;
195}
196
197static int prepare_for_access_response(struct fsnotify_group *group,
198 struct fsnotify_event *event,
199 __s32 fd)
200{
201 struct fanotify_response_event *re;
202
203 if (!(event->mask & FAN_ALL_PERM_EVENTS))
204 return 0;
205
206 re = kmem_cache_alloc(fanotify_response_event_cache, GFP_KERNEL);
207 if (!re)
208 return -ENOMEM;
209
210 re->event = FANOTIFY_E(event);
211 re->fd = fd;
212
213 mutex_lock(&group->fanotify_data.access_mutex);
214 list_add_tail(&re->list, &group->fanotify_data.access_list);
215 mutex_unlock(&group->fanotify_data.access_mutex);
216
217 return 0;
218}
219
220#else
221static int prepare_for_access_response(struct fsnotify_group *group,
222 struct fsnotify_event *event,
223 __s32 fd)
224{
225 return 0; 186 return 0;
226} 187}
227
228#endif 188#endif
229 189
230static ssize_t copy_event_to_user(struct fsnotify_group *group, 190static ssize_t copy_event_to_user(struct fsnotify_group *group,
@@ -247,9 +207,18 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group,
247 fanotify_event_metadata.event_len)) 207 fanotify_event_metadata.event_len))
248 goto out_close_fd; 208 goto out_close_fd;
249 209
250 ret = prepare_for_access_response(group, event, fd); 210#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
251 if (ret) 211 if (event->mask & FAN_ALL_PERM_EVENTS) {
252 goto out_close_fd; 212 struct fanotify_perm_event_info *pevent;
213
214 pevent = FANOTIFY_PE(event);
215 pevent->fd = fd;
216 mutex_lock(&group->fanotify_data.access_mutex);
217 list_add_tail(&pevent->fae.fse.list,
218 &group->fanotify_data.access_list);
219 mutex_unlock(&group->fanotify_data.access_mutex);
220 }
221#endif
253 222
254 if (fd != FAN_NOFD) 223 if (fd != FAN_NOFD)
255 fd_install(fd, f); 224 fd_install(fd, f);
@@ -263,7 +232,7 @@ out_close_fd:
263out: 232out:
264#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS 233#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
265 if (event->mask & FAN_ALL_PERM_EVENTS) { 234 if (event->mask & FAN_ALL_PERM_EVENTS) {
266 FANOTIFY_E(event)->response = FAN_DENY; 235 FANOTIFY_PE(event)->response = FAN_DENY;
267 wake_up(&group->fanotify_data.access_waitq); 236 wake_up(&group->fanotify_data.access_waitq);
268 } 237 }
269#endif 238#endif
@@ -312,8 +281,8 @@ static ssize_t fanotify_read(struct file *file, char __user *buf,
312 break; 281 break;
313 ret = copy_event_to_user(group, kevent, buf); 282 ret = copy_event_to_user(group, kevent, buf);
314 /* 283 /*
315 * Permission events get destroyed after we 284 * Permission events get queued to wait for response.
316 * receive response 285 * Other events can be destroyed now.
317 */ 286 */
318 if (!(kevent->mask & FAN_ALL_PERM_EVENTS)) 287 if (!(kevent->mask & FAN_ALL_PERM_EVENTS))
319 fsnotify_destroy_event(group, kevent); 288 fsnotify_destroy_event(group, kevent);
@@ -375,20 +344,19 @@ static int fanotify_release(struct inode *ignored, struct file *file)
375 struct fsnotify_group *group = file->private_data; 344 struct fsnotify_group *group = file->private_data;
376 345
377#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS 346#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
378 struct fanotify_response_event *re, *lre; 347 struct fanotify_perm_event_info *event, *next;
379 348
380 mutex_lock(&group->fanotify_data.access_mutex); 349 mutex_lock(&group->fanotify_data.access_mutex);
381 350
382 atomic_inc(&group->fanotify_data.bypass_perm); 351 atomic_inc(&group->fanotify_data.bypass_perm);
383 352
384 list_for_each_entry_safe(re, lre, &group->fanotify_data.access_list, list) { 353 list_for_each_entry_safe(event, next, &group->fanotify_data.access_list,
385 pr_debug("%s: found group=%p re=%p event=%p\n", __func__, group, 354 fae.fse.list) {
386 re, re->event); 355 pr_debug("%s: found group=%p event=%p\n", __func__, group,
387 356 event);
388 list_del_init(&re->list);
389 re->event->response = FAN_ALLOW;
390 357
391 kmem_cache_free(fanotify_response_event_cache, re); 358 list_del_init(&event->fae.fse.list);
359 event->response = FAN_ALLOW;
392 } 360 }
393 mutex_unlock(&group->fanotify_data.access_mutex); 361 mutex_unlock(&group->fanotify_data.access_mutex);
394 362
@@ -723,20 +691,15 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
723 group->fanotify_data.user = user; 691 group->fanotify_data.user = user;
724 atomic_inc(&user->fanotify_listeners); 692 atomic_inc(&user->fanotify_listeners);
725 693
726 oevent = kmem_cache_alloc(fanotify_event_cachep, GFP_KERNEL); 694 oevent = fanotify_alloc_event(NULL, FS_Q_OVERFLOW, NULL);
727 if (unlikely(!oevent)) { 695 if (unlikely(!oevent)) {
728 fd = -ENOMEM; 696 fd = -ENOMEM;
729 goto out_destroy_group; 697 goto out_destroy_group;
730 } 698 }
731 group->overflow_event = &oevent->fse; 699 group->overflow_event = &oevent->fse;
732 fsnotify_init_event(group->overflow_event, NULL, FS_Q_OVERFLOW);
733 oevent->tgid = get_pid(task_tgid(current));
734 oevent->path.mnt = NULL;
735 oevent->path.dentry = NULL;
736 700
737 group->fanotify_data.f_flags = event_f_flags; 701 group->fanotify_data.f_flags = event_f_flags;
738#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS 702#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
739 oevent->response = 0;
740 mutex_init(&group->fanotify_data.access_mutex); 703 mutex_init(&group->fanotify_data.access_mutex);
741 init_waitqueue_head(&group->fanotify_data.access_waitq); 704 init_waitqueue_head(&group->fanotify_data.access_waitq);
742 INIT_LIST_HEAD(&group->fanotify_data.access_list); 705 INIT_LIST_HEAD(&group->fanotify_data.access_list);
@@ -912,9 +875,11 @@ COMPAT_SYSCALL_DEFINE6(fanotify_mark,
912static int __init fanotify_user_setup(void) 875static int __init fanotify_user_setup(void)
913{ 876{
914 fanotify_mark_cache = KMEM_CACHE(fsnotify_mark, SLAB_PANIC); 877 fanotify_mark_cache = KMEM_CACHE(fsnotify_mark, SLAB_PANIC);
915 fanotify_response_event_cache = KMEM_CACHE(fanotify_response_event,
916 SLAB_PANIC);
917 fanotify_event_cachep = KMEM_CACHE(fanotify_event_info, SLAB_PANIC); 878 fanotify_event_cachep = KMEM_CACHE(fanotify_event_info, SLAB_PANIC);
879#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
880 fanotify_perm_event_cachep = KMEM_CACHE(fanotify_perm_event_info,
881 SLAB_PANIC);
882#endif
918 883
919 return 0; 884 return 0;
920} 885}