Blame view
fs/notify/fsnotify.c
16.8 KB
c82ee6d3b treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-or-later |
90586523e fsnotify: unified... |
2 3 |
/* * Copyright (C) 2008 Red Hat, Inc., Eric Paris <eparis@redhat.com> |
90586523e fsnotify: unified... |
4 5 6 7 |
*/ #include <linux/dcache.h> #include <linux/fs.h> |
5a0e3ad6a include cleanup: ... |
8 |
#include <linux/gfp.h> |
90586523e fsnotify: unified... |
9 10 |
#include <linux/init.h> #include <linux/module.h> |
7131485a9 fsnotify: mount p... |
11 |
#include <linux/mount.h> |
90586523e fsnotify: unified... |
12 13 14 15 16 17 |
#include <linux/srcu.h> #include <linux/fsnotify_backend.h> #include "fsnotify.h" /* |
3be25f49b fsnotify: add mar... |
18 19 20 21 22 23 24 |
* Clear all of the marks on an inode when it is being evicted from core */ void __fsnotify_inode_delete(struct inode *inode) { fsnotify_clear_marks_by_inode(inode); } EXPORT_SYMBOL_GPL(__fsnotify_inode_delete); |
ca9c726ee fsnotify: Infrast... |
25 26 27 28 |
void __fsnotify_vfsmount_delete(struct vfsmount *mnt) { fsnotify_clear_marks_by_mount(mnt); } |
ebb3b47e3 fsnotify: Drop in... |
29 30 31 32 33 34 35 |
/** * fsnotify_unmount_inodes - an sb is unmounting. handle any watched inodes. * @sb: superblock being unmounted. * * Called during unmount with no locks held, so needs to be safe against * concurrent modifiers. We temporarily drop sb->s_inode_list_lock and CAN block. */ |
1e6cb7239 fsnotify: add sup... |
36 |
static void fsnotify_unmount_inodes(struct super_block *sb) |
ebb3b47e3 fsnotify: Drop in... |
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
{ struct inode *inode, *iput_inode = NULL; spin_lock(&sb->s_inode_list_lock); list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { /* * We cannot __iget() an inode in state I_FREEING, * I_WILL_FREE, or I_NEW which is fine because by that point * the inode cannot have any associated watches. */ spin_lock(&inode->i_lock); if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) { spin_unlock(&inode->i_lock); continue; } /* * If i_count is zero, the inode cannot have any watches and |
1751e8a6c Rename superblock... |
55 |
* doing an __iget/iput with SB_ACTIVE clear would actually |
ebb3b47e3 fsnotify: Drop in... |
56 57 |
* evict all inodes with zero i_count from icache which is * unnecessarily violent and may in fact be illegal to do. |
1edc8eb2e fs: call fsnotify... |
58 59 60 |
* However, we should have been called /after/ evict_inodes * removed all zero refcount inodes, in any case. Test to * be sure. |
ebb3b47e3 fsnotify: Drop in... |
61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
*/ if (!atomic_read(&inode->i_count)) { spin_unlock(&inode->i_lock); continue; } __iget(inode); spin_unlock(&inode->i_lock); spin_unlock(&sb->s_inode_list_lock); if (iput_inode) iput(iput_inode); /* for each watch, send FS_UNMOUNT and then remove it */ |
82ace1efb fsnotify: create ... |
75 |
fsnotify_inode(inode, FS_UNMOUNT); |
ebb3b47e3 fsnotify: Drop in... |
76 77 78 79 |
fsnotify_inode_delete(inode); iput_inode = inode; |
04646aebd fs: avoid softloc... |
80 |
cond_resched(); |
ebb3b47e3 fsnotify: Drop in... |
81 82 83 84 85 86 |
spin_lock(&sb->s_inode_list_lock); } spin_unlock(&sb->s_inode_list_lock); if (iput_inode) iput(iput_inode); |
721fb6fbf fsnotify: Fix bus... |
87 88 89 |
/* Wait for outstanding inode references from connectors */ wait_var_event(&sb->s_fsnotify_inode_refs, !atomic_long_read(&sb->s_fsnotify_inode_refs)); |
ebb3b47e3 fsnotify: Drop in... |
90 |
} |
1e6cb7239 fsnotify: add sup... |
91 92 93 94 95 |
void fsnotify_sb_delete(struct super_block *sb) { fsnotify_unmount_inodes(sb); fsnotify_clear_marks_by_sb(sb); } |
3be25f49b fsnotify: add mar... |
96 |
/* |
c28f7e56e fsnotify: parent ... |
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
* Given an inode, first check if we care what happens to our children. Inotify * and dnotify both tell their parents about events. If we care about any event * on a child we run all of our children and set a dentry flag saying that the * parent cares. Thus when an event happens on a child it can quickly tell if * if there is a need to find a parent and send the event to the parent. */ void __fsnotify_update_child_dentry_flags(struct inode *inode) { struct dentry *alias; int watched; if (!S_ISDIR(inode->i_mode)) return; /* determine if the children should tell inode about their events */ watched = fsnotify_inode_watches_children(inode); |
873feea09 fs: dcache per-in... |
113 |
spin_lock(&inode->i_lock); |
c28f7e56e fsnotify: parent ... |
114 115 |
/* run all of the dentries associated with this inode. Since this is a * directory, there damn well better only be one item on this list */ |
946e51f2b move d_rcu from o... |
116 |
hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) { |
c28f7e56e fsnotify: parent ... |
117 118 119 120 121 |
struct dentry *child; /* run all of the children of the original inode and fix their * d_flags to indicate parental interest (their parent is the * original inode) */ |
2fd6b7f50 fs: dcache scale ... |
122 |
spin_lock(&alias->d_lock); |
946e51f2b move d_rcu from o... |
123 |
list_for_each_entry(child, &alias->d_subdirs, d_child) { |
c28f7e56e fsnotify: parent ... |
124 125 |
if (!child->d_inode) continue; |
2fd6b7f50 fs: dcache scale ... |
126 |
spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED); |
c28f7e56e fsnotify: parent ... |
127 128 129 130 131 132 |
if (watched) child->d_flags |= DCACHE_FSNOTIFY_PARENT_WATCHED; else child->d_flags &= ~DCACHE_FSNOTIFY_PARENT_WATCHED; spin_unlock(&child->d_lock); } |
2fd6b7f50 fs: dcache scale ... |
133 |
spin_unlock(&alias->d_lock); |
c28f7e56e fsnotify: parent ... |
134 |
} |
873feea09 fs: dcache per-in... |
135 |
spin_unlock(&inode->i_lock); |
c28f7e56e fsnotify: parent ... |
136 |
} |
9b93f3310 fsnotify: send ev... |
137 138 139 140 141 142 143 144 145 |
/* Are inode/sb/mount interested in parent and name info with this event? */ static bool fsnotify_event_needs_parent(struct inode *inode, struct mount *mnt, __u32 mask) { __u32 marks_mask = 0; /* We only send parent/name to inode/sb/mount for events on non-dir */ if (mask & FS_ISDIR) return false; |
41bf5eed8 fsnotify: fix eve... |
146 147 148 149 150 151 |
/* * All events that are possible on child can also may be reported with * parent/name info to inode/sb/mount. Otherwise, a watching parent * could result in events reported with unexpected name info to sb/mount. */ BUILD_BUG_ON(FS_EVENTS_POSS_ON_CHILD & ~FS_EVENTS_POSS_TO_PARENT); |
9b93f3310 fsnotify: send ev... |
152 153 154 155 156 157 158 159 160 |
/* Did either inode/sb/mount subscribe for events with parent/name? */ marks_mask |= fsnotify_parent_needed_mask(inode->i_fsnotify_mask); marks_mask |= fsnotify_parent_needed_mask(inode->i_sb->s_fsnotify_mask); if (mnt) marks_mask |= fsnotify_parent_needed_mask(mnt->mnt_fsnotify_mask); /* Did they subscribe for this event with parent/name info? */ return mask & marks_mask; } |
c738fbabb fsnotify: fold fs... |
161 162 |
/* * Notify this dentry's parent about a child's events with child name info |
9b93f3310 fsnotify: send ev... |
163 164 165 166 167 |
* if parent is watching or if inode/sb/mount are interested in events with * parent and name info. * * Notify only the child without name info if parent is not watching and * inode/sb/mount are not interested in events with parent and name info. |
c738fbabb fsnotify: fold fs... |
168 |
*/ |
71d734103 fsnotify: Rearran... |
169 |
int __fsnotify_parent(struct dentry *dentry, __u32 mask, const void *data, |
c738fbabb fsnotify: fold fs... |
170 |
int data_type) |
c28f7e56e fsnotify: parent ... |
171 |
{ |
9b93f3310 fsnotify: send ev... |
172 173 |
const struct path *path = fsnotify_data_path(data, data_type); struct mount *mnt = path ? real_mount(path->mnt) : NULL; |
497b0c5a7 fsnotify: send ev... |
174 |
struct inode *inode = d_inode(dentry); |
c28f7e56e fsnotify: parent ... |
175 |
struct dentry *parent; |
9b93f3310 fsnotify: send ev... |
176 |
bool parent_watched = dentry->d_flags & DCACHE_FSNOTIFY_PARENT_WATCHED; |
7372e79c9 fanotify: fix log... |
177 |
bool parent_needed, parent_interested; |
9b93f3310 fsnotify: send ev... |
178 |
__u32 p_mask; |
40a100d3a fsnotify: pass di... |
179 |
struct inode *p_inode = NULL; |
497b0c5a7 fsnotify: send ev... |
180 181 |
struct name_snapshot name; struct qstr *file_name = NULL; |
52420392c fsnotify: call fs... |
182 |
int ret = 0; |
c28f7e56e fsnotify: parent ... |
183 |
|
9b93f3310 fsnotify: send ev... |
184 185 186 187 188 189 190 |
/* * Do inode/sb/mount care about parent and name info on non-dir? * Do they care about any event at all? */ if (!inode->i_fsnotify_marks && !inode->i_sb->s_fsnotify_marks && (!mnt || !mnt->mnt_fsnotify_marks) && !parent_watched) return 0; |
497b0c5a7 fsnotify: send ev... |
191 |
parent = NULL; |
7372e79c9 fanotify: fix log... |
192 193 |
parent_needed = fsnotify_event_needs_parent(inode, mnt, mask); if (!parent_watched && !parent_needed) |
497b0c5a7 fsnotify: send ev... |
194 |
goto notify; |
c28f7e56e fsnotify: parent ... |
195 |
|
9b93f3310 fsnotify: send ev... |
196 |
/* Does parent inode care about events on children? */ |
4d4eb3667 fsnotify: use dge... |
197 |
parent = dget_parent(dentry); |
c28f7e56e fsnotify: parent ... |
198 |
p_inode = parent->d_inode; |
9b93f3310 fsnotify: send ev... |
199 200 |
p_mask = fsnotify_inode_watches_children(p_inode); if (unlikely(parent_watched && !p_mask)) |
4d4eb3667 fsnotify: use dge... |
201 |
__fsnotify_update_child_dentry_flags(p_inode); |
9b93f3310 fsnotify: send ev... |
202 203 204 |
/* * Include parent/name in notification either if some notification |
7372e79c9 fanotify: fix log... |
205 |
* groups require parent info or the parent is interested in this event. |
9b93f3310 fsnotify: send ev... |
206 |
*/ |
7372e79c9 fanotify: fix log... |
207 208 |
parent_interested = mask & p_mask & ALL_FSNOTIFY_EVENTS; if (parent_needed || parent_interested) { |
497b0c5a7 fsnotify: send ev... |
209 210 |
/* When notifying parent, child should be passed as data */ WARN_ON_ONCE(inode != fsnotify_data_inode(data, data_type)); |
49d31c2f3 dentry name snaps... |
211 |
|
497b0c5a7 fsnotify: send ev... |
212 |
/* Notify both parent and child with child name info */ |
49d31c2f3 dentry name snaps... |
213 |
take_dentry_name_snapshot(&name, dentry); |
497b0c5a7 fsnotify: send ev... |
214 |
file_name = &name.name; |
7372e79c9 fanotify: fix log... |
215 |
if (parent_interested) |
9b93f3310 fsnotify: send ev... |
216 |
mask |= FS_EVENT_ON_CHILD; |
c28f7e56e fsnotify: parent ... |
217 |
} |
497b0c5a7 fsnotify: send ev... |
218 |
notify: |
40a100d3a fsnotify: pass di... |
219 |
ret = fsnotify(mask, data, data_type, p_inode, file_name, inode, 0); |
52420392c fsnotify: call fs... |
220 |
|
497b0c5a7 fsnotify: send ev... |
221 222 223 |
if (file_name) release_dentry_name_snapshot(&name); dput(parent); |
c738fbabb fsnotify: fold fs... |
224 |
|
497b0c5a7 fsnotify: send ev... |
225 |
return ret; |
c28f7e56e fsnotify: parent ... |
226 |
} |
71d734103 fsnotify: Rearran... |
227 |
EXPORT_SYMBOL_GPL(__fsnotify_parent); |
c28f7e56e fsnotify: parent ... |
228 |
|
c9be99c86 fsnotify: general... |
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 |
static int fsnotify_handle_inode_event(struct fsnotify_group *group, struct fsnotify_mark *inode_mark, u32 mask, const void *data, int data_type, struct inode *dir, const struct qstr *name, u32 cookie) { const struct path *path = fsnotify_data_path(data, data_type); struct inode *inode = fsnotify_data_inode(data, data_type); const struct fsnotify_ops *ops = group->ops; if (WARN_ON_ONCE(!ops->handle_inode_event)) return 0; if ((inode_mark->mask & FS_EXCL_UNLINK) && path && d_unlinked(path->dentry)) return 0; |
41bf5eed8 fsnotify: fix eve... |
245 246 247 |
/* Check interest of this mark in case event was sent with two marks */ if (!(mask & inode_mark->mask & ALL_FSNOTIFY_EVENTS)) return 0; |
c9be99c86 fsnotify: general... |
248 249 |
return ops->handle_inode_event(inode_mark, mask, inode, dir, name, cookie); } |
b9a1b9772 fsnotify: create ... |
250 251 252 253 254 255 |
static int fsnotify_handle_event(struct fsnotify_group *group, __u32 mask, const void *data, int data_type, struct inode *dir, const struct qstr *name, u32 cookie, struct fsnotify_iter_info *iter_info) { struct fsnotify_mark *inode_mark = fsnotify_iter_inode_mark(iter_info); |
41bf5eed8 fsnotify: fix eve... |
256 |
struct fsnotify_mark *parent_mark = fsnotify_iter_parent_mark(iter_info); |
b9a1b9772 fsnotify: create ... |
257 |
int ret; |
b9a1b9772 fsnotify: create ... |
258 259 260 |
if (WARN_ON_ONCE(fsnotify_iter_sb_mark(iter_info)) || WARN_ON_ONCE(fsnotify_iter_vfsmount_mark(iter_info))) return 0; |
41bf5eed8 fsnotify: fix eve... |
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 |
if (parent_mark) { /* * parent_mark indicates that the parent inode is watching * children and interested in this event, which is an event * possible on child. But is *this mark* watching children and * interested in this event? */ if (parent_mark->mask & FS_EVENT_ON_CHILD) { ret = fsnotify_handle_inode_event(group, parent_mark, mask, data, data_type, dir, name, 0); if (ret) return ret; } if (!inode_mark) return 0; } if (mask & FS_EVENT_ON_CHILD) { /* * Some events can be sent on both parent dir and child marks * (e.g. FS_ATTRIB). If both parent dir and child are * watching, report the event once to parent dir with name (if * interested) and once to child without name (if interested). * The child watcher is expecting an event without a file name * and without the FS_EVENT_ON_CHILD flag. */ mask &= ~FS_EVENT_ON_CHILD; |
b9a1b9772 fsnotify: create ... |
288 289 290 |
dir = NULL; name = NULL; } |
41bf5eed8 fsnotify: fix eve... |
291 292 |
return fsnotify_handle_inode_event(group, inode_mark, mask, data, data_type, dir, name, cookie); |
b9a1b9772 fsnotify: create ... |
293 |
} |
b54cecf5e fsnotify: pass di... |
294 295 296 |
static int send_to_group(__u32 mask, const void *data, int data_type, struct inode *dir, const struct qstr *file_name, u32 cookie, struct fsnotify_iter_info *iter_info) |
7131485a9 fsnotify: mount p... |
297 |
{ |
faa9560ae fanotify: do not ... |
298 |
struct fsnotify_group *group = NULL; |
007d1e839 fsnotify: general... |
299 |
__u32 test_mask = (mask & ALL_FSNOTIFY_EVENTS); |
92183a428 fsnotify: fix ign... |
300 301 |
__u32 marks_mask = 0; __u32 marks_ignored_mask = 0; |
3dca1a749 fsnotify: general... |
302 303 |
struct fsnotify_mark *mark; int type; |
613a807fe fsnotify: walk th... |
304 |
|
5b0457ad0 fsnotify: remove ... |
305 |
if (WARN_ON(!iter_info->report_mask)) |
faa9560ae fanotify: do not ... |
306 |
return 0; |
ce8f76fb7 fsnotify: pass bo... |
307 308 309 |
/* clear ignored on inode modification */ if (mask & FS_MODIFY) { |
3dca1a749 fsnotify: general... |
310 311 312 313 314 315 316 317 |
fsnotify_foreach_obj_type(type) { if (!fsnotify_iter_should_report_type(iter_info, type)) continue; mark = iter_info->marks[type]; if (mark && !(mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)) mark->ignored_mask = 0; } |
ce8f76fb7 fsnotify: pass bo... |
318 |
} |
613a807fe fsnotify: walk th... |
319 |
|
3dca1a749 fsnotify: general... |
320 321 322 323 324 325 326 327 328 329 |
fsnotify_foreach_obj_type(type) { if (!fsnotify_iter_should_report_type(iter_info, type)) continue; mark = iter_info->marks[type]; /* does the object mark tell us to do something? */ if (mark) { group = mark->group; marks_mask |= mark->mask; marks_ignored_mask |= mark->ignored_mask; } |
ce8f76fb7 fsnotify: pass bo... |
330 |
} |
b54cecf5e fsnotify: pass di... |
331 332 333 334 |
pr_debug("%s: group=%p mask=%x marks_mask=%x marks_ignored_mask=%x data=%p data_type=%d dir=%p cookie=%d ", __func__, group, mask, marks_mask, marks_ignored_mask, data, data_type, dir, cookie); |
faa9560ae fanotify: do not ... |
335 |
|
92183a428 fsnotify: fix ign... |
336 |
if (!(test_mask & marks_mask & ~marks_ignored_mask)) |
613a807fe fsnotify: walk th... |
337 |
return 0; |
b9a1b9772 fsnotify: create ... |
338 339 340 341 342 343 344 |
if (group->ops->handle_event) { return group->ops->handle_event(group, mask, data, data_type, dir, file_name, cookie, iter_info); } return fsnotify_handle_event(group, mask, data, data_type, dir, file_name, cookie, iter_info); |
7131485a9 fsnotify: mount p... |
345 |
} |
3427ce715 fsnotify: clean u... |
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 |
static struct fsnotify_mark *fsnotify_first_mark(struct fsnotify_mark_connector **connp) { struct fsnotify_mark_connector *conn; struct hlist_node *node = NULL; conn = srcu_dereference(*connp, &fsnotify_mark_srcu); if (conn) node = srcu_dereference(conn->list.first, &fsnotify_mark_srcu); return hlist_entry_safe(node, struct fsnotify_mark, obj_list); } static struct fsnotify_mark *fsnotify_next_mark(struct fsnotify_mark *mark) { struct hlist_node *node = NULL; if (mark) node = srcu_dereference(mark->obj_list.next, &fsnotify_mark_srcu); return hlist_entry_safe(node, struct fsnotify_mark, obj_list); } |
c28f7e56e fsnotify: parent ... |
368 |
/* |
d9a6f30bb fsnotify: introdu... |
369 370 371 372 373 374 375 376 |
* iter_info is a multi head priority queue of marks. * Pick a subset of marks from queue heads, all with the * same group and set the report_mask for selected subset. * Returns the report_mask of the selected subset. */ static unsigned int fsnotify_iter_select_report_types( struct fsnotify_iter_info *iter_info) { |
47d9c7cc4 fsnotify: general... |
377 378 379 380 381 382 383 384 385 386 387 |
struct fsnotify_group *max_prio_group = NULL; struct fsnotify_mark *mark; int type; /* Choose max prio group among groups of all queue heads */ fsnotify_foreach_obj_type(type) { mark = iter_info->marks[type]; if (mark && fsnotify_compare_groups(max_prio_group, mark->group) > 0) max_prio_group = mark->group; } |
d9a6f30bb fsnotify: introdu... |
388 |
|
47d9c7cc4 fsnotify: general... |
389 |
if (!max_prio_group) |
d9a6f30bb fsnotify: introdu... |
390 |
return 0; |
47d9c7cc4 fsnotify: general... |
391 |
/* Set the report mask for marks from same group as max prio group */ |
d9a6f30bb fsnotify: introdu... |
392 |
iter_info->report_mask = 0; |
47d9c7cc4 fsnotify: general... |
393 394 395 396 397 398 |
fsnotify_foreach_obj_type(type) { mark = iter_info->marks[type]; if (mark && fsnotify_compare_groups(max_prio_group, mark->group) == 0) fsnotify_iter_set_report_type(iter_info, type); } |
d9a6f30bb fsnotify: introdu... |
399 400 401 402 403 404 405 406 407 408 |
return iter_info->report_mask; } /* * Pop from iter_info multi head queue, the marks that were iterated in the * current iteration step. */ static void fsnotify_iter_next(struct fsnotify_iter_info *iter_info) { |
47d9c7cc4 fsnotify: general... |
409 |
int type; |
d9a6f30bb fsnotify: introdu... |
410 |
|
47d9c7cc4 fsnotify: general... |
411 412 413 414 415 |
fsnotify_foreach_obj_type(type) { if (fsnotify_iter_should_report_type(iter_info, type)) iter_info->marks[type] = fsnotify_next_mark(iter_info->marks[type]); } |
d9a6f30bb fsnotify: introdu... |
416 417 418 |
} /* |
40a100d3a fsnotify: pass di... |
419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 |
* fsnotify - This is the main call to fsnotify. * * The VFS calls into hook specific functions in linux/fsnotify.h. * Those functions then in turn call here. Here will call out to all of the * registered fsnotify_group. Those groups can then use the notification event * in whatever means they feel necessary. * * @mask: event type and flags * @data: object that event happened on * @data_type: type of object for fanotify_data_XXX() accessors * @dir: optional directory associated with event - * if @file_name is not NULL, this is the directory that * @file_name is relative to * @file_name: optional file name associated with event * @inode: optional inode associated with event - * either @dir or @inode must be non-NULL. * if both are non-NULL event may be reported to both. * @cookie: inotify rename cookie |
90586523e fsnotify: unified... |
437 |
*/ |
40a100d3a fsnotify: pass di... |
438 439 |
int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir, const struct qstr *file_name, struct inode *inode, u32 cookie) |
90586523e fsnotify: unified... |
440 |
{ |
b54cecf5e fsnotify: pass di... |
441 |
const struct path *path = fsnotify_data_path(data, data_type); |
3427ce715 fsnotify: clean u... |
442 |
struct fsnotify_iter_info iter_info = {}; |
40a100d3a fsnotify: pass di... |
443 |
struct super_block *sb; |
60f7ed8c7 fsnotify: send pa... |
444 |
struct mount *mnt = NULL; |
41bf5eed8 fsnotify: fix eve... |
445 |
struct inode *parent = NULL; |
9385a84d7 fsnotify: Pass fs... |
446 |
int ret = 0; |
71d734103 fsnotify: Rearran... |
447 |
__u32 test_mask, marks_mask; |
90586523e fsnotify: unified... |
448 |
|
71d734103 fsnotify: Rearran... |
449 |
if (path) |
aa93bdc55 fsnotify: use hel... |
450 |
mnt = real_mount(path->mnt); |
613a807fe fsnotify: walk th... |
451 |
|
40a100d3a fsnotify: pass di... |
452 453 454 455 456 |
if (!inode) { /* Dirent event - report on TYPE_INODE to dir */ inode = dir; } else if (mask & FS_EVENT_ON_CHILD) { /* |
41bf5eed8 fsnotify: fix eve... |
457 458 |
* Event on child - report on TYPE_PARENT to dir if it is * watching children and on TYPE_INODE to child. |
40a100d3a fsnotify: pass di... |
459 |
*/ |
41bf5eed8 fsnotify: fix eve... |
460 |
parent = dir; |
40a100d3a fsnotify: pass di... |
461 462 |
} sb = inode->i_sb; |
497b0c5a7 fsnotify: send ev... |
463 |
|
613a807fe fsnotify: walk th... |
464 |
/* |
7c49b8616 fs/notify: optimi... |
465 466 467 468 469 470 |
* Optimization: srcu_read_lock() has a memory barrier which can * be expensive. It protects walking the *_fsnotify_marks lists. * However, if we do not walk the lists, we do not have to do * SRCU because we have no references to any objects and do not * need SRCU to keep them "alive". */ |
9b93f3310 fsnotify: send ev... |
471 |
if (!sb->s_fsnotify_marks && |
497b0c5a7 fsnotify: send ev... |
472 |
(!mnt || !mnt->mnt_fsnotify_marks) && |
9b93f3310 fsnotify: send ev... |
473 |
(!inode || !inode->i_fsnotify_marks) && |
41bf5eed8 fsnotify: fix eve... |
474 |
(!parent || !parent->i_fsnotify_marks)) |
7c49b8616 fs/notify: optimi... |
475 |
return 0; |
71d734103 fsnotify: Rearran... |
476 |
|
9b93f3310 fsnotify: send ev... |
477 |
marks_mask = sb->s_fsnotify_mask; |
497b0c5a7 fsnotify: send ev... |
478 479 |
if (mnt) marks_mask |= mnt->mnt_fsnotify_mask; |
9b93f3310 fsnotify: send ev... |
480 481 |
if (inode) marks_mask |= inode->i_fsnotify_mask; |
41bf5eed8 fsnotify: fix eve... |
482 483 |
if (parent) marks_mask |= parent->i_fsnotify_mask; |
497b0c5a7 fsnotify: send ev... |
484 |
|
71d734103 fsnotify: Rearran... |
485 |
|
7c49b8616 fs/notify: optimi... |
486 |
/* |
613a807fe fsnotify: walk th... |
487 |
* if this is a modify event we may need to clear the ignored masks |
497b0c5a7 fsnotify: send ev... |
488 |
* otherwise return if none of the marks care about this type of event. |
613a807fe fsnotify: walk th... |
489 |
*/ |
71d734103 fsnotify: Rearran... |
490 491 |
test_mask = (mask & ALL_FSNOTIFY_EVENTS); if (!(mask & FS_MODIFY) && !(test_mask & marks_mask)) |
613a807fe fsnotify: walk th... |
492 |
return 0; |
3a9fb89f4 fsnotify: include... |
493 |
|
9385a84d7 fsnotify: Pass fs... |
494 |
iter_info.srcu_idx = srcu_read_lock(&fsnotify_mark_srcu); |
7131485a9 fsnotify: mount p... |
495 |
|
45a9fb372 fsnotify: send al... |
496 497 |
iter_info.marks[FSNOTIFY_OBJ_TYPE_SB] = fsnotify_first_mark(&sb->s_fsnotify_marks); |
9bdda4e9c fsnotify: fix ign... |
498 |
if (mnt) { |
47d9c7cc4 fsnotify: general... |
499 |
iter_info.marks[FSNOTIFY_OBJ_TYPE_VFSMOUNT] = |
3427ce715 fsnotify: clean u... |
500 |
fsnotify_first_mark(&mnt->mnt_fsnotify_marks); |
90586523e fsnotify: unified... |
501 |
} |
9b93f3310 fsnotify: send ev... |
502 503 504 505 |
if (inode) { iter_info.marks[FSNOTIFY_OBJ_TYPE_INODE] = fsnotify_first_mark(&inode->i_fsnotify_marks); } |
41bf5eed8 fsnotify: fix eve... |
506 507 508 |
if (parent) { iter_info.marks[FSNOTIFY_OBJ_TYPE_PARENT] = fsnotify_first_mark(&parent->i_fsnotify_marks); |
497b0c5a7 fsnotify: send ev... |
509 |
} |
75c1be487 fsnotify: srcu to... |
510 |
|
8edc6e168 fanotify: fix not... |
511 |
/* |
60f7ed8c7 fsnotify: send pa... |
512 513 |
* We need to merge inode/vfsmount/sb mark lists so that e.g. inode mark * ignore masks are properly reflected for mount/sb mark notifications. |
8edc6e168 fanotify: fix not... |
514 515 |
* That's why this traversal is so complicated... */ |
d9a6f30bb fsnotify: introdu... |
516 |
while (fsnotify_iter_select_report_types(&iter_info)) { |
b54cecf5e fsnotify: pass di... |
517 518 |
ret = send_to_group(mask, data, data_type, dir, file_name, cookie, &iter_info); |
613a807fe fsnotify: walk th... |
519 |
|
ff8bcbd03 fsnotify: correct... |
520 521 |
if (ret && (mask & ALL_FSNOTIFY_PERM_EVENTS)) goto out; |
d9a6f30bb fsnotify: introdu... |
522 |
fsnotify_iter_next(&iter_info); |
7131485a9 fsnotify: mount p... |
523 |
} |
ff8bcbd03 fsnotify: correct... |
524 525 |
ret = 0; out: |
9385a84d7 fsnotify: Pass fs... |
526 |
srcu_read_unlock(&fsnotify_mark_srcu, iter_info.srcu_idx); |
c4ec54b40 fsnotify: new fsn... |
527 |
|
98b5c10d3 fanotify: do not ... |
528 |
return ret; |
90586523e fsnotify: unified... |
529 530 531 532 533 |
} EXPORT_SYMBOL_GPL(fsnotify); static __init int fsnotify_init(void) { |
75c1be487 fsnotify: srcu to... |
534 |
int ret; |
08b95c338 fanotify: remove ... |
535 |
BUILD_BUG_ON(HWEIGHT32(ALL_FSNOTIFY_BITS) != 25); |
20dee624c fsnotify: check t... |
536 |
|
75c1be487 fsnotify: srcu to... |
537 538 539 |
ret = init_srcu_struct(&fsnotify_mark_srcu); if (ret) panic("initializing fsnotify_mark_srcu"); |
9dd813c15 fsnotify: Move ma... |
540 541 |
fsnotify_mark_connector_cachep = KMEM_CACHE(fsnotify_mark_connector, SLAB_PANIC); |
75c1be487 fsnotify: srcu to... |
542 |
return 0; |
90586523e fsnotify: unified... |
543 |
} |
75c1be487 fsnotify: srcu to... |
544 |
core_initcall(fsnotify_init); |