Commit | Line | Data |
---|---|---|
3be25f49 EP |
1 | /* |
2 | * Copyright (C) 2008 Red Hat, Inc., Eric Paris <eparis@redhat.com> | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License as published by | |
6 | * the Free Software Foundation; either version 2, or (at your option) | |
7 | * any later version. | |
8 | * | |
9 | * This program is distributed in the hope that it will be useful, | |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | * GNU General Public License for more details. | |
13 | * | |
14 | * You should have received a copy of the GNU General Public License | |
15 | * along with this program; see the file COPYING. If not, write to | |
16 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | |
17 | */ | |
18 | ||
3be25f49 EP |
19 | #include <linux/fs.h> |
20 | #include <linux/init.h> | |
21 | #include <linux/kernel.h> | |
22 | #include <linux/module.h> | |
23 | #include <linux/mutex.h> | |
3be25f49 EP |
24 | #include <linux/spinlock.h> |
25 | ||
60063497 | 26 | #include <linux/atomic.h> |
3be25f49 EP |
27 | |
28 | #include <linux/fsnotify_backend.h> | |
29 | #include "fsnotify.h" | |
30 | ||
55fa6091 DC |
31 | #include "../internal.h" |
32 | ||
3be25f49 EP |
33 | void fsnotify_recalc_inode_mask(struct inode *inode) |
34 | { | |
a242677b | 35 | fsnotify_recalc_mask(inode->i_fsnotify_marks); |
3be25f49 EP |
36 | } |
37 | ||
e911d8af | 38 | struct inode *fsnotify_destroy_inode_mark(struct fsnotify_mark *mark) |
3be25f49 | 39 | { |
86ffe245 | 40 | struct inode *inode = mark->connector->inode; |
e911d8af | 41 | bool empty; |
3be25f49 | 42 | |
986ab098 | 43 | BUG_ON(!mutex_is_locked(&mark->group->mark_mutex)); |
5444e298 | 44 | assert_spin_locked(&mark->lock); |
3be25f49 | 45 | |
3be25f49 EP |
46 | spin_lock(&inode->i_lock); |
47 | ||
0809ab69 | 48 | hlist_del_init_rcu(&mark->obj_list); |
e911d8af | 49 | empty = hlist_empty(&mark->connector->list); |
86ffe245 | 50 | mark->connector = NULL; |
3be25f49 | 51 | |
3be25f49 | 52 | spin_unlock(&inode->i_lock); |
e911d8af | 53 | |
a242677b JK |
54 | fsnotify_recalc_mask(inode->i_fsnotify_marks); |
55 | ||
e911d8af | 56 | return empty ? inode : NULL; |
3be25f49 EP |
57 | } |
58 | ||
4d92604c EP |
59 | /* |
60 | * Given a group clear all of the inode marks associated with that group. | |
61 | */ | |
62 | void fsnotify_clear_inode_marks_by_group(struct fsnotify_group *group) | |
63 | { | |
86ffe245 | 64 | fsnotify_clear_marks_by_group_flags(group, FSNOTIFY_OBJ_TYPE_INODE); |
4d92604c EP |
65 | } |
66 | ||
3be25f49 | 67 | /* |
35566087 AG |
68 | * given a group and inode, find the mark associated with that combination. |
69 | * if found take a reference to that mark and return it, else return NULL | |
3be25f49 | 70 | */ |
5444e298 EP |
71 | struct fsnotify_mark *fsnotify_find_inode_mark(struct fsnotify_group *group, |
72 | struct inode *inode) | |
35566087 AG |
73 | { |
74 | struct fsnotify_mark *mark; | |
75 | ||
76 | spin_lock(&inode->i_lock); | |
9dd813c1 | 77 | mark = fsnotify_find_mark(inode->i_fsnotify_marks, group); |
35566087 AG |
78 | spin_unlock(&inode->i_lock); |
79 | ||
80 | return mark; | |
81 | } | |
3be25f49 | 82 | |
164bc619 EP |
83 | /** |
84 | * fsnotify_unmount_inodes - an sb is unmounting. handle any watched inodes. | |
74278da9 | 85 | * @sb: superblock being unmounted. |
164bc619 | 86 | * |
55fa6091 | 87 | * Called during unmount with no locks held, so needs to be safe against |
74278da9 | 88 | * concurrent modifiers. We temporarily drop sb->s_inode_list_lock and CAN block. |
164bc619 | 89 | */ |
74278da9 | 90 | void fsnotify_unmount_inodes(struct super_block *sb) |
164bc619 | 91 | { |
5716863e | 92 | struct inode *inode, *iput_inode = NULL; |
164bc619 | 93 | |
74278da9 | 94 | spin_lock(&sb->s_inode_list_lock); |
5716863e | 95 | list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { |
164bc619 | 96 | /* |
a4ffdde6 | 97 | * We cannot __iget() an inode in state I_FREEING, |
164bc619 EP |
98 | * I_WILL_FREE, or I_NEW which is fine because by that point |
99 | * the inode cannot have any associated watches. | |
100 | */ | |
250df6ed DC |
101 | spin_lock(&inode->i_lock); |
102 | if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) { | |
103 | spin_unlock(&inode->i_lock); | |
164bc619 | 104 | continue; |
250df6ed | 105 | } |
164bc619 EP |
106 | |
107 | /* | |
108 | * If i_count is zero, the inode cannot have any watches and | |
109 | * doing an __iget/iput with MS_ACTIVE clear would actually | |
110 | * evict all inodes with zero i_count from icache which is | |
111 | * unnecessarily violent and may in fact be illegal to do. | |
112 | */ | |
250df6ed DC |
113 | if (!atomic_read(&inode->i_count)) { |
114 | spin_unlock(&inode->i_lock); | |
164bc619 | 115 | continue; |
250df6ed | 116 | } |
164bc619 | 117 | |
5716863e | 118 | __iget(inode); |
250df6ed | 119 | spin_unlock(&inode->i_lock); |
74278da9 | 120 | spin_unlock(&sb->s_inode_list_lock); |
164bc619 | 121 | |
5716863e JK |
122 | if (iput_inode) |
123 | iput(iput_inode); | |
164bc619 EP |
124 | |
125 | /* for each watch, send FS_UNMOUNT and then remove it */ | |
126 | fsnotify(inode, FS_UNMOUNT, inode, FSNOTIFY_EVENT_INODE, NULL, 0); | |
127 | ||
128 | fsnotify_inode_delete(inode); | |
129 | ||
5716863e | 130 | iput_inode = inode; |
164bc619 | 131 | |
74278da9 | 132 | spin_lock(&sb->s_inode_list_lock); |
164bc619 | 133 | } |
74278da9 | 134 | spin_unlock(&sb->s_inode_list_lock); |
5716863e JK |
135 | |
136 | if (iput_inode) | |
137 | iput(iput_inode); | |
164bc619 | 138 | } |