Blame view

fs/notify/inode_mark.c 8.25 KB
3be25f49b   Eric Paris   fsnotify: add mar...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  /*
   *  Copyright (C) 2008 Red Hat, Inc., Eric Paris <eparis@redhat.com>
   *
   *  This program is free software; you can redistribute it and/or modify
   *  it under the terms of the GNU General Public License as published by
   *  the Free Software Foundation; either version 2, or (at your option)
   *  any later version.
   *
   *  This program is distributed in the hope that it will be useful,
   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *  GNU General Public License for more details.
   *
   *  You should have received a copy of the GNU General Public License
   *  along with this program; see the file COPYING.  If not, write to
   *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
   */
3be25f49b   Eric Paris   fsnotify: add mar...
18
19
20
21
22
  #include <linux/fs.h>
  #include <linux/init.h>
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/mutex.h>
3be25f49b   Eric Paris   fsnotify: add mar...
23
  #include <linux/spinlock.h>
164bc6195   Eric Paris   fsnotify: handle ...
24
  #include <linux/writeback.h> /* for inode_lock */
3be25f49b   Eric Paris   fsnotify: add mar...
25
26
27
28
29
  
  #include <asm/atomic.h>
  
  #include <linux/fsnotify_backend.h>
  #include "fsnotify.h"
3be25f49b   Eric Paris   fsnotify: add mar...
30
31
32
33
34
  /*
   * Recalculate the mask of events relevant to a given inode locked.
   */
  static void fsnotify_recalc_inode_mask_locked(struct inode *inode)
  {
841bdc10f   Eric Paris   fsnotify: rename ...
35
  	struct fsnotify_mark *mark;
3be25f49b   Eric Paris   fsnotify: add mar...
36
37
38
39
  	struct hlist_node *pos;
  	__u32 new_mask = 0;
  
  	assert_spin_locked(&inode->i_lock);
841bdc10f   Eric Paris   fsnotify: rename ...
40
41
  	hlist_for_each_entry(mark, pos, &inode->i_fsnotify_marks, i.i_list)
  		new_mask |= mark->mask;
3be25f49b   Eric Paris   fsnotify: add mar...
42
43
44
45
46
47
48
49
50
51
52
53
  	inode->i_fsnotify_mask = new_mask;
  }
  
  /*
   * Recalculate the inode->i_fsnotify_mask, or the mask of all FS_* event types
   * any notifier is interested in hearing for this inode.
   */
  void fsnotify_recalc_inode_mask(struct inode *inode)
  {
  	spin_lock(&inode->i_lock);
  	fsnotify_recalc_inode_mask_locked(inode);
  	spin_unlock(&inode->i_lock);
c28f7e56e   Eric Paris   fsnotify: parent ...
54
55
  
  	__fsnotify_update_child_dentry_flags(inode);
3be25f49b   Eric Paris   fsnotify: add mar...
56
  }
5444e2981   Eric Paris   fsnotify: split g...
57
  void fsnotify_destroy_inode_mark(struct fsnotify_mark *mark)
3be25f49b   Eric Paris   fsnotify: add mar...
58
  {
5444e2981   Eric Paris   fsnotify: split g...
59
  	struct inode *inode = mark->i.inode;
3be25f49b   Eric Paris   fsnotify: add mar...
60

5444e2981   Eric Paris   fsnotify: split g...
61
62
  	assert_spin_locked(&mark->lock);
  	assert_spin_locked(&mark->group->mark_lock);
3be25f49b   Eric Paris   fsnotify: add mar...
63

3be25f49b   Eric Paris   fsnotify: add mar...
64
  	spin_lock(&inode->i_lock);
a4c6e9961   Eric Paris   fsnotify: use _rc...
65
  	hlist_del_init_rcu(&mark->i.i_list);
841bdc10f   Eric Paris   fsnotify: rename ...
66
  	mark->i.inode = NULL;
3be25f49b   Eric Paris   fsnotify: add mar...
67
68
  
  	/*
e61ce8673   Eric Paris   fsnotify: rename ...
69
  	 * this mark is now off the inode->i_fsnotify_marks list and we
3be25f49b   Eric Paris   fsnotify: add mar...
70
71
72
73
74
75
  	 * hold the inode->i_lock, so this is the perfect time to update the
  	 * inode->i_fsnotify_mask
  	 */
  	fsnotify_recalc_inode_mask_locked(inode);
  
  	spin_unlock(&inode->i_lock);
3be25f49b   Eric Paris   fsnotify: add mar...
76
77
78
79
80
81
82
  }
  
  /*
   * Given an inode, destroy all of the marks associated with that inode.
   */
  void fsnotify_clear_marks_by_inode(struct inode *inode)
  {
841bdc10f   Eric Paris   fsnotify: rename ...
83
  	struct fsnotify_mark *mark, *lmark;
3be25f49b   Eric Paris   fsnotify: add mar...
84
85
86
87
  	struct hlist_node *pos, *n;
  	LIST_HEAD(free_list);
  
  	spin_lock(&inode->i_lock);
841bdc10f   Eric Paris   fsnotify: rename ...
88
89
  	hlist_for_each_entry_safe(mark, pos, n, &inode->i_fsnotify_marks, i.i_list) {
  		list_add(&mark->i.free_i_list, &free_list);
a4c6e9961   Eric Paris   fsnotify: use _rc...
90
  		hlist_del_init_rcu(&mark->i.i_list);
841bdc10f   Eric Paris   fsnotify: rename ...
91
  		fsnotify_get_mark(mark);
3be25f49b   Eric Paris   fsnotify: add mar...
92
93
  	}
  	spin_unlock(&inode->i_lock);
841bdc10f   Eric Paris   fsnotify: rename ...
94
95
96
  	list_for_each_entry_safe(mark, lmark, &free_list, i.free_i_list) {
  		fsnotify_destroy_mark(mark);
  		fsnotify_put_mark(mark);
3be25f49b   Eric Paris   fsnotify: add mar...
97
98
99
100
  	}
  }
  
  /*
4d92604cc   Eric Paris   fanotify: clear a...
101
102
103
104
105
106
107
108
   * Given a group clear all of the inode marks associated with that group.
   */
  void fsnotify_clear_inode_marks_by_group(struct fsnotify_group *group)
  {
  	fsnotify_clear_marks_by_group_flags(group, FSNOTIFY_MARK_FLAG_INODE);
  }
  
  /*
3be25f49b   Eric Paris   fsnotify: add mar...
109
110
111
   * given a group and inode, find the mark associated with that combination.
   * if found take a reference to that mark and return it, else return NULL
   */
5444e2981   Eric Paris   fsnotify: split g...
112
113
  struct fsnotify_mark *fsnotify_find_inode_mark_locked(struct fsnotify_group *group,
  						      struct inode *inode)
3be25f49b   Eric Paris   fsnotify: add mar...
114
  {
841bdc10f   Eric Paris   fsnotify: rename ...
115
  	struct fsnotify_mark *mark;
3be25f49b   Eric Paris   fsnotify: add mar...
116
117
118
  	struct hlist_node *pos;
  
  	assert_spin_locked(&inode->i_lock);
841bdc10f   Eric Paris   fsnotify: rename ...
119
120
121
122
  	hlist_for_each_entry(mark, pos, &inode->i_fsnotify_marks, i.i_list) {
  		if (mark->group == group) {
  			fsnotify_get_mark(mark);
  			return mark;
3be25f49b   Eric Paris   fsnotify: add mar...
123
124
125
126
127
128
  		}
  	}
  	return NULL;
  }
  
  /*
355660870   Andreas Gruenbacher   fsnotify: take in...
129
130
   * given a group and inode, find the mark associated with that combination.
   * if found take a reference to that mark and return it, else return NULL
3be25f49b   Eric Paris   fsnotify: add mar...
131
   */
5444e2981   Eric Paris   fsnotify: split g...
132
133
  struct fsnotify_mark *fsnotify_find_inode_mark(struct fsnotify_group *group,
  					       struct inode *inode)
355660870   Andreas Gruenbacher   fsnotify: take in...
134
135
136
137
  {
  	struct fsnotify_mark *mark;
  
  	spin_lock(&inode->i_lock);
5444e2981   Eric Paris   fsnotify: split g...
138
  	mark = fsnotify_find_inode_mark_locked(group, inode);
355660870   Andreas Gruenbacher   fsnotify: take in...
139
140
141
142
  	spin_unlock(&inode->i_lock);
  
  	return mark;
  }
3be25f49b   Eric Paris   fsnotify: add mar...
143

3be25f49b   Eric Paris   fsnotify: add mar...
144
  /*
90b1e7a57   Eric Paris   fsnotify: allow m...
145
146
147
148
149
   * If we are setting a mark mask on an inode mark we should pin the inode
   * in memory.
   */
  void fsnotify_set_inode_mark_mask_locked(struct fsnotify_mark *mark,
  					 __u32 mask)
3be25f49b   Eric Paris   fsnotify: add mar...
150
  {
90b1e7a57   Eric Paris   fsnotify: allow m...
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
  	struct inode *inode;
  
  	assert_spin_locked(&mark->lock);
  
  	if (mask &&
  	    mark->i.inode &&
  	    !(mark->flags & FSNOTIFY_MARK_FLAG_OBJECT_PINNED)) {
  		mark->flags |= FSNOTIFY_MARK_FLAG_OBJECT_PINNED;
  		inode = igrab(mark->i.inode);
  		/*
  		 * we shouldn't be able to get here if the inode wasn't
  		 * already safely held in memory.  But bug in case it
  		 * ever is wrong.
  		 */
  		BUG_ON(!inode);
  	}
3be25f49b   Eric Paris   fsnotify: add mar...
167
168
169
  }
  
  /*
0c6532e4e   Eric Paris   fsnotify: place m...
170
   * Attach an initialized mark to a given inode.
3be25f49b   Eric Paris   fsnotify: add mar...
171
   * These marks may be used for the fsnotify backend to determine which
0c6532e4e   Eric Paris   fsnotify: place m...
172
   * event types should be delivered to which group and for which inodes.  These
6ad2d4e3e   Eric Paris   fsnotify: impleme...
173
174
   * marks are ordered according to priority, highest number first, and then by
   * the group's location in memory.
3be25f49b   Eric Paris   fsnotify: add mar...
175
   */
5444e2981   Eric Paris   fsnotify: split g...
176
177
178
  int fsnotify_add_inode_mark(struct fsnotify_mark *mark,
  			    struct fsnotify_group *group, struct inode *inode,
  			    int allow_dups)
3be25f49b   Eric Paris   fsnotify: add mar...
179
  {
0c6532e4e   Eric Paris   fsnotify: place m...
180
181
  	struct fsnotify_mark *lmark;
  	struct hlist_node *node, *last = NULL;
3be25f49b   Eric Paris   fsnotify: add mar...
182
  	int ret = 0;
700307a29   Eric Paris   fsnotify: use an ...
183
  	mark->flags |= FSNOTIFY_MARK_FLAG_INODE;
098cf2fc7   Eric Paris   fsnotify: add fla...
184

5444e2981   Eric Paris   fsnotify: split g...
185
186
  	assert_spin_locked(&mark->lock);
  	assert_spin_locked(&group->mark_lock);
1ef5f13c6   Eric Paris   fsnotify: fsnotif...
187

3be25f49b   Eric Paris   fsnotify: add mar...
188
  	spin_lock(&inode->i_lock);
0c6532e4e   Eric Paris   fsnotify: place m...
189
  	mark->i.inode = inode;
9f0d793b5   Eric Paris   fsnotify: do not ...
190

0c6532e4e   Eric Paris   fsnotify: place m...
191
192
  	/* is mark the first mark? */
  	if (hlist_empty(&inode->i_fsnotify_marks)) {
a4c6e9961   Eric Paris   fsnotify: use _rc...
193
  		hlist_add_head_rcu(&mark->i.i_list, &inode->i_fsnotify_marks);
0c6532e4e   Eric Paris   fsnotify: place m...
194
195
  		goto out;
  	}
3be25f49b   Eric Paris   fsnotify: add mar...
196

0c6532e4e   Eric Paris   fsnotify: place m...
197
198
199
  	/* should mark be in the middle of the current list? */
  	hlist_for_each_entry(lmark, node, &inode->i_fsnotify_marks, i.i_list) {
  		last = node;
3be25f49b   Eric Paris   fsnotify: add mar...
200

0c6532e4e   Eric Paris   fsnotify: place m...
201
202
203
204
  		if ((lmark->group == group) && !allow_dups) {
  			ret = -EEXIST;
  			goto out;
  		}
3be25f49b   Eric Paris   fsnotify: add mar...
205

6ad2d4e3e   Eric Paris   fsnotify: impleme...
206
207
208
209
210
  		if (mark->group->priority < lmark->group->priority)
  			continue;
  
  		if ((mark->group->priority == lmark->group->priority) &&
  		    (mark->group < lmark->group))
0c6532e4e   Eric Paris   fsnotify: place m...
211
  			continue;
3be25f49b   Eric Paris   fsnotify: add mar...
212

a4c6e9961   Eric Paris   fsnotify: use _rc...
213
  		hlist_add_before_rcu(&mark->i.i_list, &lmark->i.i_list);
0c6532e4e   Eric Paris   fsnotify: place m...
214
  		goto out;
3be25f49b   Eric Paris   fsnotify: add mar...
215
  	}
0c6532e4e   Eric Paris   fsnotify: place m...
216
217
  	BUG_ON(last == NULL);
  	/* mark should be the last entry.  last is the current last entry */
a4c6e9961   Eric Paris   fsnotify: use _rc...
218
  	hlist_add_after_rcu(last, &mark->i.i_list);
0c6532e4e   Eric Paris   fsnotify: place m...
219
220
  out:
  	fsnotify_recalc_inode_mask_locked(inode);
3be25f49b   Eric Paris   fsnotify: add mar...
221
  	spin_unlock(&inode->i_lock);
3be25f49b   Eric Paris   fsnotify: add mar...
222
223
224
  
  	return ret;
  }
164bc6195   Eric Paris   fsnotify: handle ...
225
226
227
228
229
230
231
232
233
234
235
236
  
  /**
   * fsnotify_unmount_inodes - an sb is unmounting.  handle any watched inodes.
   * @list: list of inodes being unmounted (sb->s_inodes)
   *
   * Called with inode_lock held, protecting the unmounting super block's list
   * of inodes, and with iprune_mutex held, keeping shrink_icache_memory() at bay.
   * We temporarily drop inode_lock, however, and CAN block.
   */
  void fsnotify_unmount_inodes(struct list_head *list)
  {
  	struct inode *inode, *next_i, *need_iput = NULL;
63997e98a   Al Viro   split invalidate_...
237
  	spin_lock(&inode_lock);
164bc6195   Eric Paris   fsnotify: handle ...
238
239
240
241
  	list_for_each_entry_safe(inode, next_i, list, i_sb_list) {
  		struct inode *need_iput_tmp;
  
  		/*
a4ffdde6e   Al Viro   simplify checks f...
242
  		 * We cannot __iget() an inode in state I_FREEING,
164bc6195   Eric Paris   fsnotify: handle ...
243
244
245
  		 * I_WILL_FREE, or I_NEW which is fine because by that point
  		 * the inode cannot have any associated watches.
  		 */
a4ffdde6e   Al Viro   simplify checks f...
246
  		if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW))
164bc6195   Eric Paris   fsnotify: handle ...
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
  			continue;
  
  		/*
  		 * If i_count is zero, the inode cannot have any watches and
  		 * doing an __iget/iput with MS_ACTIVE clear would actually
  		 * evict all inodes with zero i_count from icache which is
  		 * unnecessarily violent and may in fact be illegal to do.
  		 */
  		if (!atomic_read(&inode->i_count))
  			continue;
  
  		need_iput_tmp = need_iput;
  		need_iput = NULL;
  
  		/* In case fsnotify_inode_delete() drops a reference. */
  		if (inode != need_iput_tmp)
  			__iget(inode);
  		else
  			need_iput_tmp = NULL;
  
  		/* In case the dropping of a reference would nuke next_i. */
  		if ((&next_i->i_sb_list != list) &&
  		    atomic_read(&next_i->i_count) &&
a4ffdde6e   Al Viro   simplify checks f...
270
  		    !(next_i->i_state & (I_FREEING | I_WILL_FREE))) {
164bc6195   Eric Paris   fsnotify: handle ...
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
  			__iget(next_i);
  			need_iput = next_i;
  		}
  
  		/*
  		 * We can safely drop inode_lock here because we hold
  		 * references on both inode and next_i.  Also no new inodes
  		 * will be added since the umount has begun.  Finally,
  		 * iprune_mutex keeps shrink_icache_memory() away.
  		 */
  		spin_unlock(&inode_lock);
  
  		if (need_iput_tmp)
  			iput(need_iput_tmp);
  
  		/* for each watch, send FS_UNMOUNT and then remove it */
  		fsnotify(inode, FS_UNMOUNT, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
  
  		fsnotify_inode_delete(inode);
  
  		iput(inode);
  
  		spin_lock(&inode_lock);
  	}
63997e98a   Al Viro   split invalidate_...
295
  	spin_unlock(&inode_lock);
164bc6195   Eric Paris   fsnotify: handle ...
296
  }