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