Blame view

fs/notify/dnotify/dnotify.c 11.4 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
  /*
   * Directory notifications for Linux.
   *
   * Copyright (C) 2000,2001,2002 Stephen Rothwell
   *
3c5119c05   Eric Paris   dnotify: reimplem...
6
7
8
   * Copyright (C) 2009 Eric Paris <Red Hat Inc>
   * dnotify was largly rewritten to use the new fsnotify infrastructure
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
   * 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.
   */
  #include <linux/fs.h>
  #include <linux/module.h>
  #include <linux/sched.h>
  #include <linux/dnotify.h>
  #include <linux/init.h>
  #include <linux/spinlock.h>
  #include <linux/slab.h>
9f3acc314   Al Viro   [PATCH] split lin...
26
  #include <linux/fdtable.h>
3c5119c05   Eric Paris   dnotify: reimplem...
27
  #include <linux/fsnotify_backend.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28

fa3536cc1   Eric Dumazet   [PATCH] Use __rea...
29
  int dir_notify_enable __read_mostly = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30

3c5119c05   Eric Paris   dnotify: reimplem...
31
  static struct kmem_cache *dnotify_struct_cache __read_mostly;
ef5e2b785   Eric Paris   dnotify: rename m...
32
  static struct kmem_cache *dnotify_mark_cache __read_mostly;
3c5119c05   Eric Paris   dnotify: reimplem...
33
34
35
36
  static struct fsnotify_group *dnotify_group __read_mostly;
  static DEFINE_MUTEX(dnotify_mark_mutex);
  
  /*
e61ce8673   Eric Paris   fsnotify: rename ...
37
   * dnotify will attach one of these to each inode (i_fsnotify_marks) which
3c5119c05   Eric Paris   dnotify: reimplem...
38
39
40
   * is being watched by dnotify.  If multiple userspace applications are watching
   * the same directory with dnotify their information is chained in dn
   */
ef5e2b785   Eric Paris   dnotify: rename m...
41
42
  struct dnotify_mark {
  	struct fsnotify_mark fsn_mark;
3c5119c05   Eric Paris   dnotify: reimplem...
43
44
  	struct dnotify_struct *dn;
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45

3c5119c05   Eric Paris   dnotify: reimplem...
46
47
48
49
50
51
52
53
  /*
   * When a process starts or stops watching an inode the set of events which
   * dnotify cares about for that inode may change.  This function runs the
   * list of everything receiving dnotify events about this directory and calculates
   * the set of all those events.  After it updates what dnotify is interested in
   * it calls the fsnotify function so it can update the set of all events relevant
   * to this inode.
   */
ef5e2b785   Eric Paris   dnotify: rename m...
54
  static void dnotify_recalc_inode_mask(struct fsnotify_mark *fsn_mark)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
  {
3c5119c05   Eric Paris   dnotify: reimplem...
56
  	__u32 new_mask, old_mask;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
  	struct dnotify_struct *dn;
ef5e2b785   Eric Paris   dnotify: rename m...
58
59
60
  	struct dnotify_mark *dn_mark  = container_of(fsn_mark,
  						     struct dnotify_mark,
  						     fsn_mark);
3c5119c05   Eric Paris   dnotify: reimplem...
61

ef5e2b785   Eric Paris   dnotify: rename m...
62
  	assert_spin_locked(&fsn_mark->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63

ef5e2b785   Eric Paris   dnotify: rename m...
64
  	old_mask = fsn_mark->mask;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
  	new_mask = 0;
ef5e2b785   Eric Paris   dnotify: rename m...
66
  	for (dn = dn_mark->dn; dn != NULL; dn = dn->dn_next)
3c5119c05   Eric Paris   dnotify: reimplem...
67
  		new_mask |= (dn->dn_mask & ~FS_DN_MULTISHOT);
90b1e7a57   Eric Paris   fsnotify: allow m...
68
  	fsnotify_set_mark_mask_locked(fsn_mark, new_mask);
3c5119c05   Eric Paris   dnotify: reimplem...
69
70
71
  
  	if (old_mask == new_mask)
  		return;
ef5e2b785   Eric Paris   dnotify: rename m...
72
73
  	if (fsn_mark->i.inode)
  		fsnotify_recalc_inode_mask(fsn_mark->i.inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74
  }
3c5119c05   Eric Paris   dnotify: reimplem...
75
76
77
78
79
80
81
82
83
  /*
   * Mains fsnotify call where events are delivered to dnotify.
   * Find the dnotify mark on the relevant inode, run the list of dnotify structs
   * on that mark and determine which of them has expressed interest in receiving
   * events of this type.  When found send the correct process and signal and
   * destroy the dnotify struct if it was not registered to receive multiple
   * events.
   */
  static int dnotify_handle_event(struct fsnotify_group *group,
ce8f76fb7   Eric Paris   fsnotify: pass bo...
84
85
  				struct fsnotify_mark *inode_mark,
  				struct fsnotify_mark *vfsmount_mark,
3c5119c05   Eric Paris   dnotify: reimplem...
86
87
  				struct fsnotify_event *event)
  {
ef5e2b785   Eric Paris   dnotify: rename m...
88
  	struct dnotify_mark *dn_mark;
3c5119c05   Eric Paris   dnotify: reimplem...
89
90
91
92
  	struct inode *to_tell;
  	struct dnotify_struct *dn;
  	struct dnotify_struct **prev;
  	struct fown_struct *fown;
945526846   Andreas Gruenbacher   dnotify: ignore F...
93
  	__u32 test_mask = event->mask & ~FS_EVENT_ON_CHILD;
3c5119c05   Eric Paris   dnotify: reimplem...
94

ce8f76fb7   Eric Paris   fsnotify: pass bo...
95
  	BUG_ON(vfsmount_mark);
3c5119c05   Eric Paris   dnotify: reimplem...
96
  	to_tell = event->to_tell;
ce8f76fb7   Eric Paris   fsnotify: pass bo...
97
  	dn_mark = container_of(inode_mark, struct dnotify_mark, fsn_mark);
3c5119c05   Eric Paris   dnotify: reimplem...
98

ce8f76fb7   Eric Paris   fsnotify: pass bo...
99
  	spin_lock(&inode_mark->lock);
ef5e2b785   Eric Paris   dnotify: rename m...
100
  	prev = &dn_mark->dn;
3c5119c05   Eric Paris   dnotify: reimplem...
101
  	while ((dn = *prev) != NULL) {
945526846   Andreas Gruenbacher   dnotify: ignore F...
102
  		if ((dn->dn_mask & test_mask) == 0) {
3c5119c05   Eric Paris   dnotify: reimplem...
103
104
105
106
107
108
109
110
111
112
  			prev = &dn->dn_next;
  			continue;
  		}
  		fown = &dn->dn_filp->f_owner;
  		send_sigio(fown, dn->dn_fd, POLL_MSG);
  		if (dn->dn_mask & FS_DN_MULTISHOT)
  			prev = &dn->dn_next;
  		else {
  			*prev = dn->dn_next;
  			kmem_cache_free(dnotify_struct_cache, dn);
ce8f76fb7   Eric Paris   fsnotify: pass bo...
113
  			dnotify_recalc_inode_mask(inode_mark);
3c5119c05   Eric Paris   dnotify: reimplem...
114
115
  		}
  	}
ce8f76fb7   Eric Paris   fsnotify: pass bo...
116
  	spin_unlock(&inode_mark->lock);
3c5119c05   Eric Paris   dnotify: reimplem...
117
118
119
120
121
122
123
124
125
  
  	return 0;
  }
  
  /*
   * Given an inode and mask determine if dnotify would be interested in sending
   * userspace notification for that pair.
   */
  static bool dnotify_should_send_event(struct fsnotify_group *group,
1968f5eed   Eric Paris   fanotify: use bot...
126
  				      struct inode *inode,
ce8f76fb7   Eric Paris   fsnotify: pass bo...
127
128
129
  				      struct fsnotify_mark *inode_mark,
  				      struct fsnotify_mark *vfsmount_mark,
  				      __u32 mask, void *data, int data_type)
3c5119c05   Eric Paris   dnotify: reimplem...
130
  {
3c5119c05   Eric Paris   dnotify: reimplem...
131
132
133
  	/* not a dir, dnotify doesn't care */
  	if (!S_ISDIR(inode->i_mode))
  		return false;
2612abb51   Eric Paris   fsnotify: cleanup...
134
  	return true;
3c5119c05   Eric Paris   dnotify: reimplem...
135
  }
ef5e2b785   Eric Paris   dnotify: rename m...
136
  static void dnotify_free_mark(struct fsnotify_mark *fsn_mark)
3c5119c05   Eric Paris   dnotify: reimplem...
137
  {
ef5e2b785   Eric Paris   dnotify: rename m...
138
139
140
  	struct dnotify_mark *dn_mark = container_of(fsn_mark,
  						    struct dnotify_mark,
  						    fsn_mark);
3c5119c05   Eric Paris   dnotify: reimplem...
141

ef5e2b785   Eric Paris   dnotify: rename m...
142
  	BUG_ON(dn_mark->dn);
3c5119c05   Eric Paris   dnotify: reimplem...
143

ef5e2b785   Eric Paris   dnotify: rename m...
144
  	kmem_cache_free(dnotify_mark_cache, dn_mark);
3c5119c05   Eric Paris   dnotify: reimplem...
145
146
147
148
149
150
  }
  
  static struct fsnotify_ops dnotify_fsnotify_ops = {
  	.handle_event = dnotify_handle_event,
  	.should_send_event = dnotify_should_send_event,
  	.free_group_priv = NULL,
a092ee20f   Eric Paris   fsnotify: allow g...
151
  	.freeing_mark = NULL,
e4aff1173   Eric Paris   fsnotify: allow g...
152
  	.free_event_priv = NULL,
3c5119c05   Eric Paris   dnotify: reimplem...
153
154
155
156
  };
  
  /*
   * Called every time a file is closed.  Looks first for a dnotify mark on the
e61ce8673   Eric Paris   fsnotify: rename ...
157
   * inode.  If one is found run all of the ->dn structures attached to that
3c5119c05   Eric Paris   dnotify: reimplem...
158
159
   * mark for one relevant to this process closing the file and remove that
   * dnotify_struct.  If that was the last dnotify_struct also remove the
e61ce8673   Eric Paris   fsnotify: rename ...
160
   * fsnotify_mark.
3c5119c05   Eric Paris   dnotify: reimplem...
161
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
163
  void dnotify_flush(struct file *filp, fl_owner_t id)
  {
ef5e2b785   Eric Paris   dnotify: rename m...
164
165
  	struct fsnotify_mark *fsn_mark;
  	struct dnotify_mark *dn_mark;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
166
167
168
  	struct dnotify_struct *dn;
  	struct dnotify_struct **prev;
  	struct inode *inode;
0f7fc9e4d   Josef "Jeff" Sipek   [PATCH] VFS: chan...
169
  	inode = filp->f_path.dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170
171
  	if (!S_ISDIR(inode->i_mode))
  		return;
3c5119c05   Eric Paris   dnotify: reimplem...
172

5444e2981   Eric Paris   fsnotify: split g...
173
  	fsn_mark = fsnotify_find_inode_mark(dnotify_group, inode);
ef5e2b785   Eric Paris   dnotify: rename m...
174
  	if (!fsn_mark)
3c5119c05   Eric Paris   dnotify: reimplem...
175
  		return;
ef5e2b785   Eric Paris   dnotify: rename m...
176
  	dn_mark = container_of(fsn_mark, struct dnotify_mark, fsn_mark);
3c5119c05   Eric Paris   dnotify: reimplem...
177
178
  
  	mutex_lock(&dnotify_mark_mutex);
ef5e2b785   Eric Paris   dnotify: rename m...
179
180
  	spin_lock(&fsn_mark->lock);
  	prev = &dn_mark->dn;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
182
183
  	while ((dn = *prev) != NULL) {
  		if ((dn->dn_owner == id) && (dn->dn_filp == filp)) {
  			*prev = dn->dn_next;
3c5119c05   Eric Paris   dnotify: reimplem...
184
  			kmem_cache_free(dnotify_struct_cache, dn);
ef5e2b785   Eric Paris   dnotify: rename m...
185
  			dnotify_recalc_inode_mask(fsn_mark);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
186
187
188
189
  			break;
  		}
  		prev = &dn->dn_next;
  	}
3c5119c05   Eric Paris   dnotify: reimplem...
190

ef5e2b785   Eric Paris   dnotify: rename m...
191
  	spin_unlock(&fsn_mark->lock);
3c5119c05   Eric Paris   dnotify: reimplem...
192
193
  
  	/* nothing else could have found us thanks to the dnotify_mark_mutex */
ef5e2b785   Eric Paris   dnotify: rename m...
194
195
  	if (dn_mark->dn == NULL)
  		fsnotify_destroy_mark(fsn_mark);
3c5119c05   Eric Paris   dnotify: reimplem...
196

3c5119c05   Eric Paris   dnotify: reimplem...
197
  	mutex_unlock(&dnotify_mark_mutex);
ef5e2b785   Eric Paris   dnotify: rename m...
198
  	fsnotify_put_mark(fsn_mark);
3c5119c05   Eric Paris   dnotify: reimplem...
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
  }
  
  /* this conversion is done only at watch creation */
  static __u32 convert_arg(unsigned long arg)
  {
  	__u32 new_mask = FS_EVENT_ON_CHILD;
  
  	if (arg & DN_MULTISHOT)
  		new_mask |= FS_DN_MULTISHOT;
  	if (arg & DN_DELETE)
  		new_mask |= (FS_DELETE | FS_MOVED_FROM);
  	if (arg & DN_MODIFY)
  		new_mask |= FS_MODIFY;
  	if (arg & DN_ACCESS)
  		new_mask |= FS_ACCESS;
  	if (arg & DN_ATTRIB)
  		new_mask |= FS_ATTRIB;
  	if (arg & DN_RENAME)
  		new_mask |= FS_DN_RENAME;
  	if (arg & DN_CREATE)
  		new_mask |= (FS_CREATE | FS_MOVED_TO);
  
  	return new_mask;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
222
  }
3c5119c05   Eric Paris   dnotify: reimplem...
223
224
  /*
   * If multiple processes watch the same inode with dnotify there is only one
e61ce8673   Eric Paris   fsnotify: rename ...
225
   * dnotify mark in inode->i_fsnotify_marks but we chain a dnotify_struct
3c5119c05   Eric Paris   dnotify: reimplem...
226
227
228
   * onto that mark.  This function either attaches the new dnotify_struct onto
   * that list, or it |= the mask onto an existing dnofiy_struct.
   */
ef5e2b785   Eric Paris   dnotify: rename m...
229
  static int attach_dn(struct dnotify_struct *dn, struct dnotify_mark *dn_mark,
3c5119c05   Eric Paris   dnotify: reimplem...
230
231
232
  		     fl_owner_t id, int fd, struct file *filp, __u32 mask)
  {
  	struct dnotify_struct *odn;
ef5e2b785   Eric Paris   dnotify: rename m...
233
  	odn = dn_mark->dn;
3c5119c05   Eric Paris   dnotify: reimplem...
234
235
236
237
238
239
240
241
242
243
244
245
246
247
  	while (odn != NULL) {
  		/* adding more events to existing dnofiy_struct? */
  		if ((odn->dn_owner == id) && (odn->dn_filp == filp)) {
  			odn->dn_fd = fd;
  			odn->dn_mask |= mask;
  			return -EEXIST;
  		}
  		odn = odn->dn_next;
  	}
  
  	dn->dn_mask = mask;
  	dn->dn_fd = fd;
  	dn->dn_filp = filp;
  	dn->dn_owner = id;
ef5e2b785   Eric Paris   dnotify: rename m...
248
249
  	dn->dn_next = dn_mark->dn;
  	dn_mark->dn = dn;
3c5119c05   Eric Paris   dnotify: reimplem...
250
251
252
253
254
255
256
257
258
  
  	return 0;
  }
  
  /*
   * When a process calls fcntl to attach a dnotify watch to a directory it ends
   * up here.  Allocate both a mark for fsnotify to add and a dnotify_struct to be
   * attached to the fsnotify_mark.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259
260
  int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
  {
ef5e2b785   Eric Paris   dnotify: rename m...
261
262
  	struct dnotify_mark *new_dn_mark, *dn_mark;
  	struct fsnotify_mark *new_fsn_mark, *fsn_mark;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
263
  	struct dnotify_struct *dn;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
264
265
  	struct inode *inode;
  	fl_owner_t id = current->files;
214b7049a   Al Viro   Fix dnotify/close...
266
  	struct file *f;
3c5119c05   Eric Paris   dnotify: reimplem...
267
268
269
270
  	int destroy = 0, error = 0;
  	__u32 mask;
  
  	/* we use these to tell if we need to kfree */
ef5e2b785   Eric Paris   dnotify: rename m...
271
  	new_fsn_mark = NULL;
3c5119c05   Eric Paris   dnotify: reimplem...
272
  	dn = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
273

3c5119c05   Eric Paris   dnotify: reimplem...
274
275
276
277
278
279
  	if (!dir_notify_enable) {
  		error = -EINVAL;
  		goto out_err;
  	}
  
  	/* a 0 mask means we are explicitly removing the watch */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
280
281
  	if ((arg & ~DN_MULTISHOT) == 0) {
  		dnotify_flush(filp, id);
3c5119c05   Eric Paris   dnotify: reimplem...
282
283
  		error = 0;
  		goto out_err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
284
  	}
3c5119c05   Eric Paris   dnotify: reimplem...
285
286
  
  	/* dnotify only works on directories */
0f7fc9e4d   Josef "Jeff" Sipek   [PATCH] VFS: chan...
287
  	inode = filp->f_path.dentry->d_inode;
3c5119c05   Eric Paris   dnotify: reimplem...
288
289
290
  	if (!S_ISDIR(inode->i_mode)) {
  		error = -ENOTDIR;
  		goto out_err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291
  	}
3c5119c05   Eric Paris   dnotify: reimplem...
292
293
294
295
296
297
  	/* expect most fcntl to add new rather than augment old */
  	dn = kmem_cache_alloc(dnotify_struct_cache, GFP_KERNEL);
  	if (!dn) {
  		error = -ENOMEM;
  		goto out_err;
  	}
214b7049a   Al Viro   Fix dnotify/close...
298

3c5119c05   Eric Paris   dnotify: reimplem...
299
  	/* new fsnotify mark, we expect most fcntl calls to add a new mark */
ef5e2b785   Eric Paris   dnotify: rename m...
300
301
  	new_dn_mark = kmem_cache_alloc(dnotify_mark_cache, GFP_KERNEL);
  	if (!new_dn_mark) {
3c5119c05   Eric Paris   dnotify: reimplem...
302
303
304
  		error = -ENOMEM;
  		goto out_err;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305

3c5119c05   Eric Paris   dnotify: reimplem...
306
307
  	/* convert the userspace DN_* "arg" to the internal FS_* defines in fsnotify */
  	mask = convert_arg(arg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
308

ef5e2b785   Eric Paris   dnotify: rename m...
309
310
311
312
313
  	/* set up the new_fsn_mark and new_dn_mark */
  	new_fsn_mark = &new_dn_mark->fsn_mark;
  	fsnotify_init_mark(new_fsn_mark, dnotify_free_mark);
  	new_fsn_mark->mask = mask;
  	new_dn_mark->dn = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
314

3c5119c05   Eric Paris   dnotify: reimplem...
315
316
  	/* this is needed to prevent the fcntl/close race described below */
  	mutex_lock(&dnotify_mark_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
317

ef5e2b785   Eric Paris   dnotify: rename m...
318
  	/* add the new_fsn_mark or find an old one. */
5444e2981   Eric Paris   fsnotify: split g...
319
  	fsn_mark = fsnotify_find_inode_mark(dnotify_group, inode);
ef5e2b785   Eric Paris   dnotify: rename m...
320
321
322
  	if (fsn_mark) {
  		dn_mark = container_of(fsn_mark, struct dnotify_mark, fsn_mark);
  		spin_lock(&fsn_mark->lock);
3c5119c05   Eric Paris   dnotify: reimplem...
323
  	} else {
5444e2981   Eric Paris   fsnotify: split g...
324
  		fsnotify_add_mark(new_fsn_mark, dnotify_group, inode, NULL, 0);
ef5e2b785   Eric Paris   dnotify: rename m...
325
326
327
328
329
  		spin_lock(&new_fsn_mark->lock);
  		fsn_mark = new_fsn_mark;
  		dn_mark = new_dn_mark;
  		/* we used new_fsn_mark, so don't free it */
  		new_fsn_mark = NULL;
3c5119c05   Eric Paris   dnotify: reimplem...
330
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
331

3c5119c05   Eric Paris   dnotify: reimplem...
332
333
334
  	rcu_read_lock();
  	f = fcheck(fd);
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
335

3c5119c05   Eric Paris   dnotify: reimplem...
336
337
  	/* if (f != filp) means that we lost a race and another task/thread
  	 * actually closed the fd we are still playing with before we grabbed
ef5e2b785   Eric Paris   dnotify: rename m...
338
  	 * the dnotify_mark_mutex and fsn_mark->lock.  Since closing the fd is the
e61ce8673   Eric Paris   fsnotify: rename ...
339
  	 * only time we clean up the marks we need to get our mark off
3c5119c05   Eric Paris   dnotify: reimplem...
340
341
342
  	 * the list. */
  	if (f != filp) {
  		/* if we added ourselves, shoot ourselves, it's possible that
ef5e2b785   Eric Paris   dnotify: rename m...
343
  		 * the flush actually did shoot this fsn_mark.  That's fine too
3c5119c05   Eric Paris   dnotify: reimplem...
344
  		 * since multiple calls to destroy_mark is perfectly safe, if
ef5e2b785   Eric Paris   dnotify: rename m...
345
  		 * we found a dn_mark already attached to the inode, just sod
3c5119c05   Eric Paris   dnotify: reimplem...
346
347
  		 * off silently as the flush at close time dealt with it.
  		 */
ef5e2b785   Eric Paris   dnotify: rename m...
348
  		if (dn_mark == new_dn_mark)
3c5119c05   Eric Paris   dnotify: reimplem...
349
350
351
  			destroy = 1;
  		goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352

3c5119c05   Eric Paris   dnotify: reimplem...
353
354
355
  	error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0);
  	if (error) {
  		/* if we added, we must shoot */
ef5e2b785   Eric Paris   dnotify: rename m...
356
  		if (dn_mark == new_dn_mark)
3c5119c05   Eric Paris   dnotify: reimplem...
357
358
  			destroy = 1;
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
359
  	}
3c5119c05   Eric Paris   dnotify: reimplem...
360

ef5e2b785   Eric Paris   dnotify: rename m...
361
362
  	error = attach_dn(dn, dn_mark, id, fd, filp, mask);
  	/* !error means that we attached the dn to the dn_mark, so don't free it */
3c5119c05   Eric Paris   dnotify: reimplem...
363
364
365
366
367
368
  	if (!error)
  		dn = NULL;
  	/* -EEXIST means that we didn't add this new dn and used an old one.
  	 * that isn't an error (and the unused dn should be freed) */
  	else if (error == -EEXIST)
  		error = 0;
ef5e2b785   Eric Paris   dnotify: rename m...
369
  	dnotify_recalc_inode_mask(fsn_mark);
3c5119c05   Eric Paris   dnotify: reimplem...
370
  out:
ef5e2b785   Eric Paris   dnotify: rename m...
371
  	spin_unlock(&fsn_mark->lock);
3c5119c05   Eric Paris   dnotify: reimplem...
372
373
  
  	if (destroy)
ef5e2b785   Eric Paris   dnotify: rename m...
374
  		fsnotify_destroy_mark(fsn_mark);
3c5119c05   Eric Paris   dnotify: reimplem...
375

3c5119c05   Eric Paris   dnotify: reimplem...
376
  	mutex_unlock(&dnotify_mark_mutex);
ef5e2b785   Eric Paris   dnotify: rename m...
377
  	fsnotify_put_mark(fsn_mark);
3c5119c05   Eric Paris   dnotify: reimplem...
378
  out_err:
ef5e2b785   Eric Paris   dnotify: rename m...
379
380
  	if (new_fsn_mark)
  		fsnotify_put_mark(new_fsn_mark);
3c5119c05   Eric Paris   dnotify: reimplem...
381
382
383
  	if (dn)
  		kmem_cache_free(dnotify_struct_cache, dn);
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
384
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
385
386
387
  
  static int __init dnotify_init(void)
  {
3c5119c05   Eric Paris   dnotify: reimplem...
388
  	dnotify_struct_cache = KMEM_CACHE(dnotify_struct, SLAB_PANIC);
ef5e2b785   Eric Paris   dnotify: rename m...
389
  	dnotify_mark_cache = KMEM_CACHE(dnotify_mark, SLAB_PANIC);
3c5119c05   Eric Paris   dnotify: reimplem...
390

0d2e2a1d0   Eric Paris   fsnotify: drop ma...
391
  	dnotify_group = fsnotify_alloc_group(&dnotify_fsnotify_ops);
3c5119c05   Eric Paris   dnotify: reimplem...
392
393
394
  	if (IS_ERR(dnotify_group))
  		panic("unable to allocate fsnotify group for dnotify
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
395
396
397
398
  	return 0;
  }
  
  module_init(dnotify_init)