Merge branch 'stable-3.2' into pandora-3.2
[pandora-kernel.git] / fs / aufs / hfsnotify.c
1 /*
2  * Copyright (C) 2005-2012 Junjiro R. Okajima
3  *
4  * This program, aufs 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 of the License, or
7  * (at your option) 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; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18
19 /*
20  * fsnotify for the lower directories
21  */
22
23 #include "aufs.h"
24
25 /* FS_IN_IGNORED is unnecessary */
26 static const __u32 AuHfsnMask = (FS_MOVED_TO | FS_MOVED_FROM | FS_DELETE
27                                  | FS_CREATE | FS_EVENT_ON_CHILD);
28 static DECLARE_WAIT_QUEUE_HEAD(au_hfsn_wq);
29
30 static void au_hfsn_free_mark(struct fsnotify_mark *mark)
31 {
32         struct au_hnotify *hn = container_of(mark, struct au_hnotify,
33                                              hn_mark);
34         AuDbg("here\n");
35         hn->hn_mark_dead = 1;
36         smp_mb();
37         wake_up_all(&au_hfsn_wq);
38 }
39
40 static int au_hfsn_alloc(struct au_hinode *hinode)
41 {
42         struct au_hnotify *hn;
43         struct super_block *sb;
44         struct au_branch *br;
45         struct fsnotify_mark *mark;
46         aufs_bindex_t bindex;
47
48         hn = hinode->hi_notify;
49         sb = hn->hn_aufs_inode->i_sb;
50         bindex = au_br_index(sb, hinode->hi_id);
51         br = au_sbr(sb, bindex);
52         hn->hn_mark_dead = 0;
53         mark = &hn->hn_mark;
54         fsnotify_init_mark(mark, au_hfsn_free_mark);
55         mark->mask = AuHfsnMask;
56         /*
57          * by udba rename or rmdir, aufs assign a new inode to the known
58          * h_inode, so specify 1 to allow dups.
59          */
60         return fsnotify_add_mark(mark, br->br_hfsn_group, hinode->hi_inode,
61                                  /*mnt*/NULL, /*allow_dups*/1);
62 }
63
64 static void au_hfsn_free(struct au_hinode *hinode)
65 {
66         struct au_hnotify *hn;
67         struct fsnotify_mark *mark;
68
69         hn = hinode->hi_notify;
70         mark = &hn->hn_mark;
71         fsnotify_destroy_mark(mark);
72         fsnotify_put_mark(mark);
73
74         /* TODO: bad approach */
75         wait_event(au_hfsn_wq, hn->hn_mark_dead);
76 }
77
78 /* ---------------------------------------------------------------------- */
79
80 static void au_hfsn_ctl(struct au_hinode *hinode, int do_set)
81 {
82         struct fsnotify_mark *mark;
83
84         mark = &hinode->hi_notify->hn_mark;
85         spin_lock(&mark->lock);
86         if (do_set) {
87                 AuDebugOn(mark->mask & AuHfsnMask);
88                 mark->mask |= AuHfsnMask;
89         } else {
90                 AuDebugOn(!(mark->mask & AuHfsnMask));
91                 mark->mask &= ~AuHfsnMask;
92         }
93         spin_unlock(&mark->lock);
94         /* fsnotify_recalc_inode_mask(hinode->hi_inode); */
95 }
96
97 /* ---------------------------------------------------------------------- */
98
99 /* #define AuDbgHnotify */
100 #ifdef AuDbgHnotify
101 static char *au_hfsn_name(u32 mask)
102 {
103 #ifdef CONFIG_AUFS_DEBUG
104 #define test_ret(flag)  if (mask & flag) \
105                                 return #flag;
106         test_ret(FS_ACCESS);
107         test_ret(FS_MODIFY);
108         test_ret(FS_ATTRIB);
109         test_ret(FS_CLOSE_WRITE);
110         test_ret(FS_CLOSE_NOWRITE);
111         test_ret(FS_OPEN);
112         test_ret(FS_MOVED_FROM);
113         test_ret(FS_MOVED_TO);
114         test_ret(FS_CREATE);
115         test_ret(FS_DELETE);
116         test_ret(FS_DELETE_SELF);
117         test_ret(FS_MOVE_SELF);
118         test_ret(FS_UNMOUNT);
119         test_ret(FS_Q_OVERFLOW);
120         test_ret(FS_IN_IGNORED);
121         test_ret(FS_IN_ISDIR);
122         test_ret(FS_IN_ONESHOT);
123         test_ret(FS_EVENT_ON_CHILD);
124         return "";
125 #undef test_ret
126 #else
127         return "??";
128 #endif
129 }
130 #endif
131
132 /* ---------------------------------------------------------------------- */
133
134 static int au_hfsn_handle_event(struct fsnotify_group *group,
135                                 struct fsnotify_mark *inode_mark,
136                                 struct fsnotify_mark *vfsmount_mark,
137                                 struct fsnotify_event *event)
138 {
139         int err;
140         struct au_hnotify *hnotify;
141         struct inode *h_dir, *h_inode;
142         __u32 mask;
143         struct qstr h_child_qstr = {
144                 .name   = event->file_name,
145                 .len    = event->name_len
146         };
147
148         AuDebugOn(event->data_type != FSNOTIFY_EVENT_INODE);
149
150         err = 0;
151         /* if FS_UNMOUNT happens, there must be another bug */
152         mask = event->mask;
153         AuDebugOn(mask & FS_UNMOUNT);
154         if (mask & (FS_IN_IGNORED | FS_UNMOUNT))
155                 goto out;
156
157         h_dir = event->to_tell;
158         h_inode = event->inode;
159 #ifdef AuDbgHnotify
160         au_debug(1);
161         if (1 || h_child_qstr.len != sizeof(AUFS_XINO_FNAME) - 1
162             || strncmp(h_child_qstr.name, AUFS_XINO_FNAME, h_child_qstr.len)) {
163                 AuDbg("i%lu, mask 0x%x %s, hcname %.*s, hi%lu\n",
164                       h_dir->i_ino, mask, au_hfsn_name(mask),
165                       AuLNPair(&h_child_qstr), h_inode ? h_inode->i_ino : 0);
166                 /* WARN_ON(1); */
167         }
168         au_debug(0);
169 #endif
170
171         AuDebugOn(!inode_mark);
172         hnotify = container_of(inode_mark, struct au_hnotify, hn_mark);
173         err = au_hnotify(h_dir, hnotify, mask, &h_child_qstr, h_inode);
174
175 out:
176         return err;
177 }
178
179 /* isn't it waste to ask every registered 'group'? */
180 /* copied from linux/fs/notify/inotify/inotify_fsnotiry.c */
181 /* it should be exported to modules */
182 static bool au_hfsn_should_send_event(struct fsnotify_group *group,
183                                       struct inode *h_inode,
184                                       struct fsnotify_mark *inode_mark,
185                                       struct fsnotify_mark *vfsmount_mark,
186                                       __u32 mask, void *data, int data_type)
187 {
188         mask = (mask & ~FS_EVENT_ON_CHILD);
189         return inode_mark->mask & mask;
190 }
191
192 static struct fsnotify_ops au_hfsn_ops = {
193         .should_send_event      = au_hfsn_should_send_event,
194         .handle_event           = au_hfsn_handle_event
195 };
196
197 /* ---------------------------------------------------------------------- */
198
199 static void au_hfsn_fin_br(struct au_branch *br)
200 {
201         if (br->br_hfsn_group)
202                 fsnotify_put_group(br->br_hfsn_group);
203 }
204
205 static int au_hfsn_init_br(struct au_branch *br, int perm)
206 {
207         br->br_hfsn_group = NULL;
208         br->br_hfsn_ops = au_hfsn_ops;
209         return 0;
210 }
211
212 static int au_hfsn_reset_br(unsigned int udba, struct au_branch *br, int perm)
213 {
214         int err;
215
216         err = 0;
217         if (udba != AuOpt_UDBA_HNOTIFY
218             || !au_br_hnotifyable(perm)) {
219                 au_hfsn_fin_br(br);
220                 br->br_hfsn_group = NULL;
221                 goto out;
222         }
223
224         if (br->br_hfsn_group)
225                 goto out;
226
227         br->br_hfsn_group = fsnotify_alloc_group(&br->br_hfsn_ops);
228         if (IS_ERR(br->br_hfsn_group)) {
229                 err = PTR_ERR(br->br_hfsn_group);
230                 pr_err("fsnotify_alloc_group() failed, %d\n", err);
231                 br->br_hfsn_group = NULL;
232         }
233
234 out:
235         AuTraceErr(err);
236         return err;
237 }
238
239 const struct au_hnotify_op au_hnotify_op = {
240         .ctl            = au_hfsn_ctl,
241         .alloc          = au_hfsn_alloc,
242         .free           = au_hfsn_free,
243
244         .reset_br       = au_hfsn_reset_br,
245         .fin_br         = au_hfsn_fin_br,
246         .init_br        = au_hfsn_init_br
247 };