1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16#include <linux/fs.h>
17#include <linux/sched.h>
18#include <linux/dnotify.h>
19#include <linux/init.h>
20#include <linux/spinlock.h>
21#include <linux/slab.h>
22
23extern void send_sigio(struct fown_struct *fown, int fd, int band);
24
25int dir_notify_enable = 1;
26
27static rwlock_t dn_lock = RW_LOCK_UNLOCKED;
28static kmem_cache_t *dn_cache;
29
30static void redo_inode_mask(struct inode *inode)
31{
32 unsigned long new_mask;
33 struct dnotify_struct *dn;
34
35 new_mask = 0;
36 for (dn = inode->i_dnotify; dn != NULL; dn = dn->dn_next)
37 new_mask |= dn->dn_mask & ~DN_MULTISHOT;
38 inode->i_dnotify_mask = new_mask;
39}
40
41void dnotify_flush(struct file *filp, fl_owner_t id)
42{
43 struct dnotify_struct *dn;
44 struct dnotify_struct **prev;
45 struct inode *inode;
46
47 inode = filp->f_dentry->d_inode;
48 if (!S_ISDIR(inode->i_mode))
49 return;
50 write_lock(&dn_lock);
51 prev = &inode->i_dnotify;
52 while ((dn = *prev) != NULL) {
53 if ((dn->dn_owner == id) && (dn->dn_filp == filp)) {
54 *prev = dn->dn_next;
55 redo_inode_mask(inode);
56 kmem_cache_free(dn_cache, dn);
57 break;
58 }
59 prev = &dn->dn_next;
60 }
61 write_unlock(&dn_lock);
62}
63
64int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
65{
66 struct dnotify_struct *dn;
67 struct dnotify_struct *odn;
68 struct dnotify_struct **prev;
69 struct inode *inode;
70 fl_owner_t id = current->files;
71 int error = 0;
72
73 if ((arg & ~DN_MULTISHOT) == 0) {
74 dnotify_flush(filp, id);
75 return 0;
76 }
77 if (!dir_notify_enable)
78 return -EINVAL;
79 inode = filp->f_dentry->d_inode;
80 if (!S_ISDIR(inode->i_mode))
81 return -ENOTDIR;
82 dn = kmem_cache_alloc(dn_cache, SLAB_KERNEL);
83 if (dn == NULL)
84 return -ENOMEM;
85 write_lock(&dn_lock);
86 prev = &inode->i_dnotify;
87 while ((odn = *prev) != NULL) {
88 if ((odn->dn_owner == id) && (odn->dn_filp == filp)) {
89 odn->dn_fd = fd;
90 odn->dn_mask |= arg;
91 inode->i_dnotify_mask |= arg & ~DN_MULTISHOT;
92 goto out_free;
93 }
94 prev = &odn->dn_next;
95 }
96
97 error = f_setown(filp, current->pid, 1);
98 if (error)
99 goto out_free;
100
101 dn->dn_mask = arg;
102 dn->dn_fd = fd;
103 dn->dn_filp = filp;
104 dn->dn_owner = id;
105 inode->i_dnotify_mask |= arg & ~DN_MULTISHOT;
106 dn->dn_next = inode->i_dnotify;
107 inode->i_dnotify = dn;
108out:
109 write_unlock(&dn_lock);
110 return error;
111out_free:
112 kmem_cache_free(dn_cache, dn);
113 goto out;
114}
115
116void __inode_dir_notify(struct inode *inode, unsigned long event)
117{
118 struct dnotify_struct * dn;
119 struct dnotify_struct **prev;
120 struct fown_struct * fown;
121 int changed = 0;
122
123 write_lock(&dn_lock);
124 prev = &inode->i_dnotify;
125 while ((dn = *prev) != NULL) {
126 if ((dn->dn_mask & event) == 0) {
127 prev = &dn->dn_next;
128 continue;
129 }
130 fown = &dn->dn_filp->f_owner;
131 send_sigio(fown, dn->dn_fd, POLL_MSG);
132 if (dn->dn_mask & DN_MULTISHOT)
133 prev = &dn->dn_next;
134 else {
135 *prev = dn->dn_next;
136 changed = 1;
137 kmem_cache_free(dn_cache, dn);
138 }
139 }
140 if (changed)
141 redo_inode_mask(inode);
142 write_unlock(&dn_lock);
143}
144
145static int __init dnotify_init(void)
146{
147 dn_cache = kmem_cache_create("dnotify cache",
148 sizeof(struct dnotify_struct), 0, 0, NULL, NULL);
149 if (!dn_cache)
150 panic("cannot create dnotify slab cache");
151 return 0;
152}
153
154module_init(dnotify_init)
155