2 * Copyright (C) 2005-2013 Junjiro R. Okajima
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.
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.
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
20 * sub-routines for dentry cache
25 static void au_dpage_free(struct au_dpage *dpage)
31 for (i = 0; i < dpage->ndentry; i++)
33 free_page((unsigned long)dpage->dentries);
36 int au_dpages_init(struct au_dcsub_pages *dpages, gfp_t gfp)
42 dpages->dpages = kmalloc(sizeof(*dpages->dpages), gfp);
43 if (unlikely(!dpages->dpages))
46 p = (void *)__get_free_page(gfp);
50 dpages->dpages[0].ndentry = 0;
51 dpages->dpages[0].dentries = p;
53 return 0; /* success */
56 kfree(dpages->dpages);
61 void au_dpages_free(struct au_dcsub_pages *dpages)
67 for (i = 0; i < dpages->ndpage; i++)
69 kfree(dpages->dpages);
72 static int au_dpages_append(struct au_dcsub_pages *dpages,
73 struct dentry *dentry, gfp_t gfp)
76 struct au_dpage *dpage;
79 dpage = dpages->dpages + dpages->ndpage - 1;
80 sz = PAGE_SIZE / sizeof(dentry);
81 if (unlikely(dpage->ndentry >= sz)) {
84 sz = dpages->ndpage * sizeof(*dpages->dpages);
85 p = au_kzrealloc(dpages->dpages, sz,
86 sz + sizeof(*dpages->dpages), gfp);
91 dpage = dpages->dpages + dpages->ndpage;
92 p = (void *)__get_free_page(gfp);
101 AuDebugOn(!dentry->d_count);
102 dpage->dentries[dpage->ndentry++] = dget_dlock(dentry);
103 return 0; /* success */
109 int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root,
110 au_dpages_test test, void *arg)
113 struct dentry *this_parent;
114 struct list_head *next;
115 struct super_block *sb = root->d_sb;
118 write_seqlock(&rename_lock);
120 spin_lock(&this_parent->d_lock);
122 next = this_parent->d_subdirs.next;
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);
134 while (next != &this_parent->d_subdirs) {
135 struct list_head *tmp = next;
136 struct dentry *dentry = list_entry(tmp, struct dentry,
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,
146 this_parent = dentry;
147 spin_acquire(&this_parent->d_lock.dep_map, 0, 1,
151 if (dentry->d_sb == sb
153 && (!test || test(dentry, arg)))
154 err = au_dpages_append(dpages, dentry,
157 spin_unlock(&dentry->d_lock);
162 if (this_parent != root) {
164 struct dentry *child;
166 tmp = this_parent->d_parent;
168 spin_unlock(&this_parent->d_lock);
171 spin_lock(&this_parent->d_lock);
173 next = child->d_child.next;
178 spin_unlock(&this_parent->d_lock);
179 write_sequnlock(&rename_lock);
183 int au_dcsub_pages_rev(struct au_dcsub_pages *dpages, struct dentry *dentry,
184 int do_include, au_dpages_test test, void *arg)
189 write_seqlock(&rename_lock);
190 spin_lock(&dentry->d_lock);
193 && (!test || test(dentry, arg)))
194 err = au_dpages_append(dpages, dentry, GFP_ATOMIC);
195 spin_unlock(&dentry->d_lock);
200 * vfsmount_lock is unnecessary since this is a traverse in a single
203 while (!IS_ROOT(dentry)) {
204 dentry = dentry->d_parent; /* rename_lock is locked */
205 spin_lock(&dentry->d_lock);
207 && (!test || test(dentry, arg)))
208 err = au_dpages_append(dpages, dentry, GFP_ATOMIC);
209 spin_unlock(&dentry->d_lock);
215 write_sequnlock(&rename_lock);
219 static inline int au_dcsub_dpages_aufs(struct dentry *dentry, void *arg)
221 return au_di(dentry) && dentry->d_sb == arg;
224 int au_dcsub_pages_rev_aufs(struct au_dcsub_pages *dpages,
225 struct dentry *dentry, int do_include)
227 return au_dcsub_pages_rev(dpages, dentry, do_include,
228 au_dcsub_dpages_aufs, dentry->d_sb);
231 int au_test_subdir(struct dentry *d1, struct dentry *d2)
233 struct path path[2] = {
242 return path_is_under(path + 0, path + 1);