Blame view
fs/notify/dnotify/dnotify.c
11.4 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 |
/* * Directory notifications for Linux. * * Copyright (C) 2000,2001,2002 Stephen Rothwell * |
3c5119c05 dnotify: reimplem... |
6 7 8 |
* Copyright (C) 2009 Eric Paris <Red Hat Inc> * dnotify was largly rewritten to use the new fsnotify infrastructure * |
1da177e4c 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 [PATCH] split lin... |
26 |
#include <linux/fdtable.h> |
3c5119c05 dnotify: reimplem... |
27 |
#include <linux/fsnotify_backend.h> |
1da177e4c Linux-2.6.12-rc2 |
28 |
|
fa3536cc1 [PATCH] Use __rea... |
29 |
int dir_notify_enable __read_mostly = 1; |
1da177e4c Linux-2.6.12-rc2 |
30 |
|
3c5119c05 dnotify: reimplem... |
31 |
static struct kmem_cache *dnotify_struct_cache __read_mostly; |
ef5e2b785 dnotify: rename m... |
32 |
static struct kmem_cache *dnotify_mark_cache __read_mostly; |
3c5119c05 dnotify: reimplem... |
33 34 35 36 |
static struct fsnotify_group *dnotify_group __read_mostly; static DEFINE_MUTEX(dnotify_mark_mutex); /* |
e61ce8673 fsnotify: rename ... |
37 |
* dnotify will attach one of these to each inode (i_fsnotify_marks) which |
3c5119c05 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 dnotify: rename m... |
41 42 |
struct dnotify_mark { struct fsnotify_mark fsn_mark; |
3c5119c05 dnotify: reimplem... |
43 44 |
struct dnotify_struct *dn; }; |
1da177e4c Linux-2.6.12-rc2 |
45 |
|
3c5119c05 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 dnotify: rename m... |
54 |
static void dnotify_recalc_inode_mask(struct fsnotify_mark *fsn_mark) |
1da177e4c Linux-2.6.12-rc2 |
55 |
{ |
3c5119c05 dnotify: reimplem... |
56 |
__u32 new_mask, old_mask; |
1da177e4c Linux-2.6.12-rc2 |
57 |
struct dnotify_struct *dn; |
ef5e2b785 dnotify: rename m... |
58 59 60 |
struct dnotify_mark *dn_mark = container_of(fsn_mark, struct dnotify_mark, fsn_mark); |
3c5119c05 dnotify: reimplem... |
61 |
|
ef5e2b785 dnotify: rename m... |
62 |
assert_spin_locked(&fsn_mark->lock); |
1da177e4c Linux-2.6.12-rc2 |
63 |
|
ef5e2b785 dnotify: rename m... |
64 |
old_mask = fsn_mark->mask; |
1da177e4c Linux-2.6.12-rc2 |
65 |
new_mask = 0; |
ef5e2b785 dnotify: rename m... |
66 |
for (dn = dn_mark->dn; dn != NULL; dn = dn->dn_next) |
3c5119c05 dnotify: reimplem... |
67 |
new_mask |= (dn->dn_mask & ~FS_DN_MULTISHOT); |
90b1e7a57 fsnotify: allow m... |
68 |
fsnotify_set_mark_mask_locked(fsn_mark, new_mask); |
3c5119c05 dnotify: reimplem... |
69 70 71 |
if (old_mask == new_mask) return; |
ef5e2b785 dnotify: rename m... |
72 73 |
if (fsn_mark->i.inode) fsnotify_recalc_inode_mask(fsn_mark->i.inode); |
1da177e4c Linux-2.6.12-rc2 |
74 |
} |
3c5119c05 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 fsnotify: pass bo... |
84 85 |
struct fsnotify_mark *inode_mark, struct fsnotify_mark *vfsmount_mark, |
3c5119c05 dnotify: reimplem... |
86 87 |
struct fsnotify_event *event) { |
ef5e2b785 dnotify: rename m... |
88 |
struct dnotify_mark *dn_mark; |
3c5119c05 dnotify: reimplem... |
89 90 91 92 |
struct inode *to_tell; struct dnotify_struct *dn; struct dnotify_struct **prev; struct fown_struct *fown; |
945526846 dnotify: ignore F... |
93 |
__u32 test_mask = event->mask & ~FS_EVENT_ON_CHILD; |
3c5119c05 dnotify: reimplem... |
94 |
|
ce8f76fb7 fsnotify: pass bo... |
95 |
BUG_ON(vfsmount_mark); |
3c5119c05 dnotify: reimplem... |
96 |
to_tell = event->to_tell; |
ce8f76fb7 fsnotify: pass bo... |
97 |
dn_mark = container_of(inode_mark, struct dnotify_mark, fsn_mark); |
3c5119c05 dnotify: reimplem... |
98 |
|
ce8f76fb7 fsnotify: pass bo... |
99 |
spin_lock(&inode_mark->lock); |
ef5e2b785 dnotify: rename m... |
100 |
prev = &dn_mark->dn; |
3c5119c05 dnotify: reimplem... |
101 |
while ((dn = *prev) != NULL) { |
945526846 dnotify: ignore F... |
102 |
if ((dn->dn_mask & test_mask) == 0) { |
3c5119c05 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 fsnotify: pass bo... |
113 |
dnotify_recalc_inode_mask(inode_mark); |
3c5119c05 dnotify: reimplem... |
114 115 |
} } |
ce8f76fb7 fsnotify: pass bo... |
116 |
spin_unlock(&inode_mark->lock); |
3c5119c05 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 fanotify: use bot... |
126 |
struct inode *inode, |
ce8f76fb7 fsnotify: pass bo... |
127 128 129 |
struct fsnotify_mark *inode_mark, struct fsnotify_mark *vfsmount_mark, __u32 mask, void *data, int data_type) |
3c5119c05 dnotify: reimplem... |
130 |
{ |
3c5119c05 dnotify: reimplem... |
131 132 133 |
/* not a dir, dnotify doesn't care */ if (!S_ISDIR(inode->i_mode)) return false; |
2612abb51 fsnotify: cleanup... |
134 |
return true; |
3c5119c05 dnotify: reimplem... |
135 |
} |
ef5e2b785 dnotify: rename m... |
136 |
static void dnotify_free_mark(struct fsnotify_mark *fsn_mark) |
3c5119c05 dnotify: reimplem... |
137 |
{ |
ef5e2b785 dnotify: rename m... |
138 139 140 |
struct dnotify_mark *dn_mark = container_of(fsn_mark, struct dnotify_mark, fsn_mark); |
3c5119c05 dnotify: reimplem... |
141 |
|
ef5e2b785 dnotify: rename m... |
142 |
BUG_ON(dn_mark->dn); |
3c5119c05 dnotify: reimplem... |
143 |
|
ef5e2b785 dnotify: rename m... |
144 |
kmem_cache_free(dnotify_mark_cache, dn_mark); |
3c5119c05 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 fsnotify: allow g... |
151 |
.freeing_mark = NULL, |
e4aff1173 fsnotify: allow g... |
152 |
.free_event_priv = NULL, |
3c5119c05 dnotify: reimplem... |
153 154 155 156 |
}; /* * Called every time a file is closed. Looks first for a dnotify mark on the |
e61ce8673 fsnotify: rename ... |
157 |
* inode. If one is found run all of the ->dn structures attached to that |
3c5119c05 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 fsnotify: rename ... |
160 |
* fsnotify_mark. |
3c5119c05 dnotify: reimplem... |
161 |
*/ |
1da177e4c Linux-2.6.12-rc2 |
162 163 |
void dnotify_flush(struct file *filp, fl_owner_t id) { |
ef5e2b785 dnotify: rename m... |
164 165 |
struct fsnotify_mark *fsn_mark; struct dnotify_mark *dn_mark; |
1da177e4c Linux-2.6.12-rc2 |
166 167 168 |
struct dnotify_struct *dn; struct dnotify_struct **prev; struct inode *inode; |
0f7fc9e4d [PATCH] VFS: chan... |
169 |
inode = filp->f_path.dentry->d_inode; |
1da177e4c Linux-2.6.12-rc2 |
170 171 |
if (!S_ISDIR(inode->i_mode)) return; |
3c5119c05 dnotify: reimplem... |
172 |
|
5444e2981 fsnotify: split g... |
173 |
fsn_mark = fsnotify_find_inode_mark(dnotify_group, inode); |
ef5e2b785 dnotify: rename m... |
174 |
if (!fsn_mark) |
3c5119c05 dnotify: reimplem... |
175 |
return; |
ef5e2b785 dnotify: rename m... |
176 |
dn_mark = container_of(fsn_mark, struct dnotify_mark, fsn_mark); |
3c5119c05 dnotify: reimplem... |
177 178 |
mutex_lock(&dnotify_mark_mutex); |
ef5e2b785 dnotify: rename m... |
179 180 |
spin_lock(&fsn_mark->lock); prev = &dn_mark->dn; |
1da177e4c 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 dnotify: reimplem... |
184 |
kmem_cache_free(dnotify_struct_cache, dn); |
ef5e2b785 dnotify: rename m... |
185 |
dnotify_recalc_inode_mask(fsn_mark); |
1da177e4c Linux-2.6.12-rc2 |
186 187 188 189 |
break; } prev = &dn->dn_next; } |
3c5119c05 dnotify: reimplem... |
190 |
|
ef5e2b785 dnotify: rename m... |
191 |
spin_unlock(&fsn_mark->lock); |
3c5119c05 dnotify: reimplem... |
192 193 |
/* nothing else could have found us thanks to the dnotify_mark_mutex */ |
ef5e2b785 dnotify: rename m... |
194 195 |
if (dn_mark->dn == NULL) fsnotify_destroy_mark(fsn_mark); |
3c5119c05 dnotify: reimplem... |
196 |
|
3c5119c05 dnotify: reimplem... |
197 |
mutex_unlock(&dnotify_mark_mutex); |
ef5e2b785 dnotify: rename m... |
198 |
fsnotify_put_mark(fsn_mark); |
3c5119c05 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 Linux-2.6.12-rc2 |
222 |
} |
3c5119c05 dnotify: reimplem... |
223 224 |
/* * If multiple processes watch the same inode with dnotify there is only one |
e61ce8673 fsnotify: rename ... |
225 |
* dnotify mark in inode->i_fsnotify_marks but we chain a dnotify_struct |
3c5119c05 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 dnotify: rename m... |
229 |
static int attach_dn(struct dnotify_struct *dn, struct dnotify_mark *dn_mark, |
3c5119c05 dnotify: reimplem... |
230 231 232 |
fl_owner_t id, int fd, struct file *filp, __u32 mask) { struct dnotify_struct *odn; |
ef5e2b785 dnotify: rename m... |
233 |
odn = dn_mark->dn; |
3c5119c05 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 dnotify: rename m... |
248 249 |
dn->dn_next = dn_mark->dn; dn_mark->dn = dn; |
3c5119c05 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 Linux-2.6.12-rc2 |
259 260 |
int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg) { |
ef5e2b785 dnotify: rename m... |
261 262 |
struct dnotify_mark *new_dn_mark, *dn_mark; struct fsnotify_mark *new_fsn_mark, *fsn_mark; |
1da177e4c Linux-2.6.12-rc2 |
263 |
struct dnotify_struct *dn; |
1da177e4c Linux-2.6.12-rc2 |
264 265 |
struct inode *inode; fl_owner_t id = current->files; |
214b7049a Fix dnotify/close... |
266 |
struct file *f; |
3c5119c05 dnotify: reimplem... |
267 268 269 270 |
int destroy = 0, error = 0; __u32 mask; /* we use these to tell if we need to kfree */ |
ef5e2b785 dnotify: rename m... |
271 |
new_fsn_mark = NULL; |
3c5119c05 dnotify: reimplem... |
272 |
dn = NULL; |
1da177e4c Linux-2.6.12-rc2 |
273 |
|
3c5119c05 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 Linux-2.6.12-rc2 |
280 281 |
if ((arg & ~DN_MULTISHOT) == 0) { dnotify_flush(filp, id); |
3c5119c05 dnotify: reimplem... |
282 283 |
error = 0; goto out_err; |
1da177e4c Linux-2.6.12-rc2 |
284 |
} |
3c5119c05 dnotify: reimplem... |
285 286 |
/* dnotify only works on directories */ |
0f7fc9e4d [PATCH] VFS: chan... |
287 |
inode = filp->f_path.dentry->d_inode; |
3c5119c05 dnotify: reimplem... |
288 289 290 |
if (!S_ISDIR(inode->i_mode)) { error = -ENOTDIR; goto out_err; |
1da177e4c Linux-2.6.12-rc2 |
291 |
} |
3c5119c05 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 Fix dnotify/close... |
298 |
|
3c5119c05 dnotify: reimplem... |
299 |
/* new fsnotify mark, we expect most fcntl calls to add a new mark */ |
ef5e2b785 dnotify: rename m... |
300 301 |
new_dn_mark = kmem_cache_alloc(dnotify_mark_cache, GFP_KERNEL); if (!new_dn_mark) { |
3c5119c05 dnotify: reimplem... |
302 303 304 |
error = -ENOMEM; goto out_err; } |
1da177e4c Linux-2.6.12-rc2 |
305 |
|
3c5119c05 dnotify: reimplem... |
306 307 |
/* convert the userspace DN_* "arg" to the internal FS_* defines in fsnotify */ mask = convert_arg(arg); |
1da177e4c Linux-2.6.12-rc2 |
308 |
|
ef5e2b785 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 Linux-2.6.12-rc2 |
314 |
|
3c5119c05 dnotify: reimplem... |
315 316 |
/* this is needed to prevent the fcntl/close race described below */ mutex_lock(&dnotify_mark_mutex); |
1da177e4c Linux-2.6.12-rc2 |
317 |
|
ef5e2b785 dnotify: rename m... |
318 |
/* add the new_fsn_mark or find an old one. */ |
5444e2981 fsnotify: split g... |
319 |
fsn_mark = fsnotify_find_inode_mark(dnotify_group, inode); |
ef5e2b785 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 dnotify: reimplem... |
323 |
} else { |
5444e2981 fsnotify: split g... |
324 |
fsnotify_add_mark(new_fsn_mark, dnotify_group, inode, NULL, 0); |
ef5e2b785 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 dnotify: reimplem... |
330 |
} |
1da177e4c Linux-2.6.12-rc2 |
331 |
|
3c5119c05 dnotify: reimplem... |
332 333 334 |
rcu_read_lock(); f = fcheck(fd); rcu_read_unlock(); |
1da177e4c Linux-2.6.12-rc2 |
335 |
|
3c5119c05 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 dnotify: rename m... |
338 |
* the dnotify_mark_mutex and fsn_mark->lock. Since closing the fd is the |
e61ce8673 fsnotify: rename ... |
339 |
* only time we clean up the marks we need to get our mark off |
3c5119c05 dnotify: reimplem... |
340 341 342 |
* the list. */ if (f != filp) { /* if we added ourselves, shoot ourselves, it's possible that |
ef5e2b785 dnotify: rename m... |
343 |
* the flush actually did shoot this fsn_mark. That's fine too |
3c5119c05 dnotify: reimplem... |
344 |
* since multiple calls to destroy_mark is perfectly safe, if |
ef5e2b785 dnotify: rename m... |
345 |
* we found a dn_mark already attached to the inode, just sod |
3c5119c05 dnotify: reimplem... |
346 347 |
* off silently as the flush at close time dealt with it. */ |
ef5e2b785 dnotify: rename m... |
348 |
if (dn_mark == new_dn_mark) |
3c5119c05 dnotify: reimplem... |
349 350 351 |
destroy = 1; goto out; } |
1da177e4c Linux-2.6.12-rc2 |
352 |
|
3c5119c05 dnotify: reimplem... |
353 354 355 |
error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0); if (error) { /* if we added, we must shoot */ |
ef5e2b785 dnotify: rename m... |
356 |
if (dn_mark == new_dn_mark) |
3c5119c05 dnotify: reimplem... |
357 358 |
destroy = 1; goto out; |
1da177e4c Linux-2.6.12-rc2 |
359 |
} |
3c5119c05 dnotify: reimplem... |
360 |
|
ef5e2b785 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 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 dnotify: rename m... |
369 |
dnotify_recalc_inode_mask(fsn_mark); |
3c5119c05 dnotify: reimplem... |
370 |
out: |
ef5e2b785 dnotify: rename m... |
371 |
spin_unlock(&fsn_mark->lock); |
3c5119c05 dnotify: reimplem... |
372 373 |
if (destroy) |
ef5e2b785 dnotify: rename m... |
374 |
fsnotify_destroy_mark(fsn_mark); |
3c5119c05 dnotify: reimplem... |
375 |
|
3c5119c05 dnotify: reimplem... |
376 |
mutex_unlock(&dnotify_mark_mutex); |
ef5e2b785 dnotify: rename m... |
377 |
fsnotify_put_mark(fsn_mark); |
3c5119c05 dnotify: reimplem... |
378 |
out_err: |
ef5e2b785 dnotify: rename m... |
379 380 |
if (new_fsn_mark) fsnotify_put_mark(new_fsn_mark); |
3c5119c05 dnotify: reimplem... |
381 382 383 |
if (dn) kmem_cache_free(dnotify_struct_cache, dn); return error; |
1da177e4c Linux-2.6.12-rc2 |
384 |
} |
1da177e4c Linux-2.6.12-rc2 |
385 386 387 |
static int __init dnotify_init(void) { |
3c5119c05 dnotify: reimplem... |
388 |
dnotify_struct_cache = KMEM_CACHE(dnotify_struct, SLAB_PANIC); |
ef5e2b785 dnotify: rename m... |
389 |
dnotify_mark_cache = KMEM_CACHE(dnotify_mark, SLAB_PANIC); |
3c5119c05 dnotify: reimplem... |
390 |
|
0d2e2a1d0 fsnotify: drop ma... |
391 |
dnotify_group = fsnotify_alloc_group(&dnotify_fsnotify_ops); |
3c5119c05 dnotify: reimplem... |
392 393 394 |
if (IS_ERR(dnotify_group)) panic("unable to allocate fsnotify group for dnotify "); |
1da177e4c Linux-2.6.12-rc2 |
395 396 397 398 |
return 0; } module_init(dnotify_init) |