Commit e4aff117368cfdd3567ee41844d216d079b55173

Authored by Eric Paris
1 parent 47882c6f51

fsnotify: allow groups to add private data to events

inotify needs per group information attached to events.  This patch allows
groups to attach private information and implements a callback so that
information can be freed when an event is being destroyed.

Signed-off-by: Eric Paris <eparis@redhat.com>
Acked-by: Al Viro <viro@zeniv.linux.org.uk>
Cc: Christoph Hellwig <hch@lst.de>

Showing 3 changed files with 68 additions and 9 deletions Side-by-side Diff

fs/notify/dnotify/dnotify.c
... ... @@ -183,6 +183,7 @@
183 183 .should_send_event = dnotify_should_send_event,
184 184 .free_group_priv = NULL,
185 185 .freeing_mark = dnotify_freeing_mark,
  186 + .free_event_priv = NULL,
186 187 };
187 188  
188 189 /*
fs/notify/notification.c
... ... @@ -90,6 +90,8 @@
90 90 if (event->data_type == FSNOTIFY_EVENT_PATH)
91 91 path_put(&event->path);
92 92  
  93 + BUG_ON(!list_empty(&event->private_data_list));
  94 +
93 95 kfree(event->file_name);
94 96 kmem_cache_free(fsnotify_event_cachep, event);
95 97 }
96 98  
... ... @@ -106,8 +108,30 @@
106 108 }
107 109  
108 110 /*
109   - * check if 2 events contain the same information.
  111 + * Find the private data that the group previously attached to this event when
  112 + * the group added the event to the notification queue (fsnotify_add_notify_event)
110 113 */
  114 +struct fsnotify_event_private_data *fsnotify_remove_priv_from_event(struct fsnotify_group *group, struct fsnotify_event *event)
  115 +{
  116 + struct fsnotify_event_private_data *lpriv;
  117 + struct fsnotify_event_private_data *priv = NULL;
  118 +
  119 + assert_spin_locked(&event->lock);
  120 +
  121 + list_for_each_entry(lpriv, &event->private_data_list, event_list) {
  122 + if (lpriv->group == group) {
  123 + priv = lpriv;
  124 + list_del(&priv->event_list);
  125 + break;
  126 + }
  127 + }
  128 + return priv;
  129 +}
  130 +
  131 +/*
  132 + * Check if 2 events contain the same information. We do not compare private data
  133 + * but at this moment that isn't a problem for any know fsnotify listeners.
  134 + */
111 135 static bool event_compare(struct fsnotify_event *old, struct fsnotify_event *new)
112 136 {
113 137 if ((old->mask == new->mask) &&
114 138  
... ... @@ -134,13 +158,17 @@
134 158 * event off the queue to deal with. If the event is successfully added to the
135 159 * group's notification queue, a reference is taken on event.
136 160 */
137   -int fsnotify_add_notify_event(struct fsnotify_group *group, struct fsnotify_event *event)
  161 +int fsnotify_add_notify_event(struct fsnotify_group *group, struct fsnotify_event *event,
  162 + struct fsnotify_event_private_data *priv)
138 163 {
139 164 struct fsnotify_event_holder *holder = NULL;
140 165 struct list_head *list = &group->notification_list;
141 166 struct fsnotify_event_holder *last_holder;
142 167 struct fsnotify_event *last_event;
143 168  
  169 + /* easy to tell if priv was attached to the event */
  170 + INIT_LIST_HEAD(&priv->event_list);
  171 +
144 172 /*
145 173 * There is one fsnotify_event_holder embedded inside each fsnotify_event.
146 174 * Check if we expect to be able to use that holder. If not alloc a new
147 175  
... ... @@ -158,8 +186,11 @@
158 186  
159 187 mutex_lock(&group->notification_mutex);
160 188  
161   - if (group->q_len >= group->max_events)
  189 + if (group->q_len >= group->max_events) {
162 190 event = &q_overflow_event;
  191 + /* sorry, no private data on the overflow event */
  192 + priv = NULL;
  193 + }
163 194  
164 195 spin_lock(&event->lock);
165 196  
... ... @@ -183,7 +214,7 @@
183 214 mutex_unlock(&group->notification_mutex);
184 215 if (holder != &event->holder)
185 216 fsnotify_destroy_event_holder(holder);
186   - return 0;
  217 + return -EEXIST;
187 218 }
188 219 }
189 220  
... ... @@ -192,6 +223,8 @@
192 223  
193 224 fsnotify_get_event(event);
194 225 list_add_tail(&holder->event_list, list);
  226 + if (priv)
  227 + list_add_tail(&priv->event_list, &event->private_data_list);
195 228 spin_unlock(&event->lock);
196 229 mutex_unlock(&group->notification_mutex);
197 230  
198 231  
... ... @@ -252,10 +285,19 @@
252 285 void fsnotify_flush_notify(struct fsnotify_group *group)
253 286 {
254 287 struct fsnotify_event *event;
  288 + struct fsnotify_event_private_data *priv;
255 289  
256 290 mutex_lock(&group->notification_mutex);
257 291 while (!fsnotify_notify_queue_is_empty(group)) {
258 292 event = fsnotify_remove_notify_event(group);
  293 + /* if they don't implement free_event_priv they better not have attached any */
  294 + if (group->ops->free_event_priv) {
  295 + spin_lock(&event->lock);
  296 + priv = fsnotify_remove_priv_from_event(group, event);
  297 + spin_unlock(&event->lock);
  298 + if (priv)
  299 + group->ops->free_event_priv(priv);
  300 + }
259 301 fsnotify_put_event(event); /* matches fsnotify_add_notify_event */
260 302 }
261 303 mutex_unlock(&group->notification_mutex);
... ... @@ -273,6 +315,8 @@
273 315 event->path.mnt = NULL;
274 316 event->inode = NULL;
275 317 event->data_type = FSNOTIFY_EVENT_NONE;
  318 +
  319 + INIT_LIST_HEAD(&event->private_data_list);
276 320  
277 321 event->to_tell = NULL;
278 322  
include/linux/fsnotify_backend.h
... ... @@ -63,6 +63,7 @@
63 63 struct fsnotify_group;
64 64 struct fsnotify_event;
65 65 struct fsnotify_mark_entry;
  66 +struct fsnotify_event_private_data;
66 67  
67 68 /*
68 69 * Each group much define these ops. The fsnotify infrastructure will call
... ... @@ -81,6 +82,7 @@
81 82 int (*handle_event)(struct fsnotify_group *group, struct fsnotify_event *event);
82 83 void (*free_group_priv)(struct fsnotify_group *group);
83 84 void (*freeing_mark)(struct fsnotify_mark_entry *entry, struct fsnotify_group *group);
  85 + void (*free_event_priv)(struct fsnotify_event_private_data *priv);
84 86 };
85 87  
86 88 /*
... ... @@ -158,6 +160,15 @@
158 160 };
159 161  
160 162 /*
  163 + * Inotify needs to tack data onto an event. This struct lets us later find the
  164 + * correct private data of the correct group.
  165 + */
  166 +struct fsnotify_event_private_data {
  167 + struct fsnotify_group *group;
  168 + struct list_head event_list;
  169 +};
  170 +
  171 +/*
161 172 * all of the information about the original object we want to now send to
162 173 * a group. If you want to carry more info from the accessing task to the
163 174 * listener this structure is where you need to be adding fields.
... ... @@ -196,6 +207,8 @@
196 207 u32 sync_cookie; /* used to corrolate events, namely inotify mv events */
197 208 char *file_name;
198 209 size_t name_len;
  210 +
  211 + struct list_head private_data_list; /* groups can store private data here */
199 212 };
200 213  
201 214 /*
202 215  
203 216  
... ... @@ -294,17 +307,18 @@
294 307 /* take a reference to an event */
295 308 extern void fsnotify_get_event(struct fsnotify_event *event);
296 309 extern void fsnotify_put_event(struct fsnotify_event *event);
297   -/* find private data previously attached to an event */
298   -extern struct fsnotify_event_private_data *fsnotify_get_priv_from_event(struct fsnotify_group *group,
299   - struct fsnotify_event *event);
  310 +/* find private data previously attached to an event and unlink it */
  311 +extern struct fsnotify_event_private_data *fsnotify_remove_priv_from_event(struct fsnotify_group *group,
  312 + struct fsnotify_event *event);
300 313  
301 314 /* attach the event to the group notification queue */
302   -extern int fsnotify_add_notify_event(struct fsnotify_group *group, struct fsnotify_event *event);
  315 +extern int fsnotify_add_notify_event(struct fsnotify_group *group, struct fsnotify_event *event,
  316 + struct fsnotify_event_private_data *priv);
303 317 /* true if the group notification queue is empty */
304 318 extern bool fsnotify_notify_queue_is_empty(struct fsnotify_group *group);
305 319 /* return, but do not dequeue the first event on the notification queue */
306 320 extern struct fsnotify_event *fsnotify_peek_notify_event(struct fsnotify_group *group);
307   -/* reutnr AND dequeue the first event on the notification queue */
  321 +/* return AND dequeue the first event on the notification queue */
308 322 extern struct fsnotify_event *fsnotify_remove_notify_event(struct fsnotify_group *group);
309 323  
310 324 /* functions used to manipulate the marks attached to inodes */