Merge branch 'stable-3.2' into pandora-3.2
[pandora-kernel.git] / fs / aufs / dcsub.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  * sub-routines for dentry cache
21  */
22
23 #include "aufs.h"
24
25 static void au_dpage_free(struct au_dpage *dpage)
26 {
27         int i;
28         struct dentry **p;
29
30         p = dpage->dentries;
31         for (i = 0; i < dpage->ndentry; i++)
32                 dput(*p++);
33         free_page((unsigned long)dpage->dentries);
34 }
35
36 int au_dpages_init(struct au_dcsub_pages *dpages, gfp_t gfp)
37 {
38         int err;
39         void *p;
40
41         err = -ENOMEM;
42         dpages->dpages = kmalloc(sizeof(*dpages->dpages), gfp);
43         if (unlikely(!dpages->dpages))
44                 goto out;
45
46         p = (void *)__get_free_page(gfp);
47         if (unlikely(!p))
48                 goto out_dpages;
49
50         dpages->dpages[0].ndentry = 0;
51         dpages->dpages[0].dentries = p;
52         dpages->ndpage = 1;
53         return 0; /* success */
54
55 out_dpages:
56         kfree(dpages->dpages);
57 out:
58         return err;
59 }
60
61 void au_dpages_free(struct au_dcsub_pages *dpages)
62 {
63         int i;
64         struct au_dpage *p;
65
66         p = dpages->dpages;
67         for (i = 0; i < dpages->ndpage; i++)
68                 au_dpage_free(p++);
69         kfree(dpages->dpages);
70 }
71
72 static int au_dpages_append(struct au_dcsub_pages *dpages,
73                             struct dentry *dentry, gfp_t gfp)
74 {
75         int err, sz;
76         struct au_dpage *dpage;
77         void *p;
78
79         dpage = dpages->dpages + dpages->ndpage - 1;
80         sz = PAGE_SIZE / sizeof(dentry);
81         if (unlikely(dpage->ndentry >= sz)) {
82                 AuLabel(new dpage);
83                 err = -ENOMEM;
84                 sz = dpages->ndpage * sizeof(*dpages->dpages);
85                 p = au_kzrealloc(dpages->dpages, sz,
86                                  sz + sizeof(*dpages->dpages), gfp);
87                 if (unlikely(!p))
88                         goto out;
89
90                 dpages->dpages = p;
91                 dpage = dpages->dpages + dpages->ndpage;
92                 p = (void *)__get_free_page(gfp);
93                 if (unlikely(!p))
94                         goto out;
95
96                 dpage->ndentry = 0;
97                 dpage->dentries = p;
98                 dpages->ndpage++;
99         }
100
101         AuDebugOn(!dentry->d_count);
102         dpage->dentries[dpage->ndentry++] = dget_dlock(dentry);
103         return 0; /* success */
104
105 out:
106         return err;
107 }
108
109 int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root,
110                    au_dpages_test test, void *arg)
111 {
112         int err;
113         struct dentry *this_parent;
114         struct list_head *next;
115         struct super_block *sb = root->d_sb;
116
117         err = 0;
118         write_seqlock(&rename_lock);
119         this_parent = root;
120         spin_lock(&this_parent->d_lock);
121 repeat:
122         next = this_parent->d_subdirs.next;
123 resume:
124         if (this_parent->d_sb == sb
125             && !IS_ROOT(this_parent)
126             && au_di(this_parent)
127             && this_parent->d_count
128             && (!test || test(this_parent, arg))) {
129                 err = au_dpages_append(dpages, this_parent, GFP_ATOMIC);
130                 if (unlikely(err))
131                         goto out;
132         }
133
134         while (next != &this_parent->d_subdirs) {
135                 struct list_head *tmp = next;
136                 struct dentry *dentry = list_entry(tmp, struct dentry,
137                                                    d_u.d_child);
138
139                 next = tmp->next;
140                 spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
141                 if (dentry->d_count) {
142                         if (!list_empty(&dentry->d_subdirs)) {
143                                 spin_unlock(&this_parent->d_lock);
144                                 spin_release(&dentry->d_lock.dep_map, 1,
145                                              _RET_IP_);
146                                 this_parent = dentry;
147                                 spin_acquire(&this_parent->d_lock.dep_map, 0, 1,
148                                              _RET_IP_);
149                                 goto repeat;
150                         }
151                         if (dentry->d_sb == sb
152                             && au_di(dentry)
153                             && (!test || test(dentry, arg)))
154                                 err = au_dpages_append(dpages, dentry,
155                                                        GFP_ATOMIC);
156                 }
157                 spin_unlock(&dentry->d_lock);
158                 if (unlikely(err))
159                         goto out;
160         }
161
162         if (this_parent != root) {
163                 struct dentry *tmp;
164                 struct dentry *child;
165
166                 tmp = this_parent->d_parent;
167                 rcu_read_lock();
168                 spin_unlock(&this_parent->d_lock);
169                 child = this_parent;
170                 this_parent = tmp;
171                 spin_lock(&this_parent->d_lock);
172                 rcu_read_unlock();
173                 next = child->d_u.d_child.next;
174                 goto resume;
175         }
176
177 out:
178         spin_unlock(&this_parent->d_lock);
179         write_sequnlock(&rename_lock);
180         return err;
181 }
182
183 int au_dcsub_pages_rev(struct au_dcsub_pages *dpages, struct dentry *dentry,
184                        int do_include, au_dpages_test test, void *arg)
185 {
186         int err;
187
188         err = 0;
189         write_seqlock(&rename_lock);
190         spin_lock(&dentry->d_lock);
191         if (do_include
192             && dentry->d_count
193             && (!test || test(dentry, arg)))
194                 err = au_dpages_append(dpages, dentry, GFP_ATOMIC);
195         spin_unlock(&dentry->d_lock);
196         if (unlikely(err))
197                 goto out;
198
199         /*
200          * vfsmount_lock is unnecessary since this is a traverse in a single
201          * mount
202          */
203         while (!IS_ROOT(dentry)) {
204                 dentry = dentry->d_parent; /* rename_lock is locked */
205                 spin_lock(&dentry->d_lock);
206                 if (dentry->d_count
207                     && (!test || test(dentry, arg)))
208                         err = au_dpages_append(dpages, dentry, GFP_ATOMIC);
209                 spin_unlock(&dentry->d_lock);
210                 if (unlikely(err))
211                         break;
212         }
213
214 out:
215         write_sequnlock(&rename_lock);
216         return err;
217 }
218
219 static inline int au_dcsub_dpages_aufs(struct dentry *dentry, void *arg)
220 {
221         return au_di(dentry) && dentry->d_sb == arg;
222 }
223
224 int au_dcsub_pages_rev_aufs(struct au_dcsub_pages *dpages,
225                             struct dentry *dentry, int do_include)
226 {
227         return au_dcsub_pages_rev(dpages, dentry, do_include,
228                                   au_dcsub_dpages_aufs, dentry->d_sb);
229 }
230
231 int au_test_subdir(struct dentry *d1, struct dentry *d2)
232 {
233         struct path path[2] = {
234                 {
235                         .dentry = d1
236                 },
237                 {
238                         .dentry = d2
239                 }
240         };
241
242         return path_is_under(path + 0, path + 1);
243 }