]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blob - fs/aufs/module.c
UBUNTU: SAUCE: aufs: bugfix, for v4.10, copy-up on XFS branch
[mirror_ubuntu-zesty-kernel.git] / fs / aufs / module.c
1 /*
2 * Copyright (C) 2005-2016 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, see <http://www.gnu.org/licenses/>.
16 */
17
18 /*
19 * module global variables and operations
20 */
21
22 #include <linux/module.h>
23 #include <linux/seq_file.h>
24 #include "aufs.h"
25
26 /* shrinkable realloc */
27 void *au_krealloc(void *p, unsigned int new_sz, gfp_t gfp, int may_shrink)
28 {
29 size_t sz;
30 int diff;
31
32 sz = 0;
33 diff = -1;
34 if (p) {
35 #if 0 /* unused */
36 if (!new_sz) {
37 au_delayed_kfree(p);
38 p = NULL;
39 goto out;
40 }
41 #else
42 AuDebugOn(!new_sz);
43 #endif
44 sz = ksize(p);
45 diff = au_kmidx_sub(sz, new_sz);
46 }
47 if (sz && !diff)
48 goto out;
49
50 if (sz < new_sz)
51 /* expand or SLOB */
52 p = krealloc(p, new_sz, gfp);
53 else if (new_sz < sz && may_shrink) {
54 /* shrink */
55 void *q;
56
57 q = kmalloc(new_sz, gfp);
58 if (q) {
59 if (p) {
60 memcpy(q, p, new_sz);
61 au_delayed_kfree(p);
62 }
63 p = q;
64 } else
65 p = NULL;
66 }
67
68 out:
69 return p;
70 }
71
72 void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp,
73 int may_shrink)
74 {
75 p = au_krealloc(p, new_sz, gfp, may_shrink);
76 if (p && new_sz > nused)
77 memset(p + nused, 0, new_sz - nused);
78 return p;
79 }
80
81 /* ---------------------------------------------------------------------- */
82 /*
83 * aufs caches
84 */
85
86 struct au_dfree au_dfree;
87
88 /* delayed free */
89 static void au_do_dfree(struct work_struct *work __maybe_unused)
90 {
91 struct llist_head *head;
92 struct llist_node *node, *next;
93
94 #define AU_CACHE_DFREE_DO_BODY(name, idx, lnode) do { \
95 head = &au_dfree.cache[AuCache_##idx].llist; \
96 node = llist_del_all(head); \
97 for (; node; node = next) { \
98 struct au_##name *p \
99 = llist_entry(node, struct au_##name, \
100 lnode); \
101 next = llist_next(node); \
102 au_cache_free_##name(p); \
103 } \
104 } while (0)
105
106 AU_CACHE_DFREE_DO_BODY(dinfo, DINFO, di_lnode);
107 AU_CACHE_DFREE_DO_BODY(icntnr, ICNTNR, lnode);
108 AU_CACHE_DFREE_DO_BODY(finfo, FINFO, fi_lnode);
109 AU_CACHE_DFREE_DO_BODY(vdir, VDIR, vd_lnode);
110 AU_CACHE_DFREE_DO_BODY(vdir_dehstr, DEHSTR, lnode);
111 #ifdef CONFIG_AUFS_HNOTIFY
112 AU_CACHE_DFREE_DO_BODY(hnotify, HNOTIFY, hn_lnode);
113 #endif
114
115 #define AU_DFREE_DO_BODY(llist, func) do { \
116 node = llist_del_all(llist); \
117 for (; node; node = next) { \
118 next = llist_next(node); \
119 func(node); \
120 } \
121 } while (0)
122
123 AU_DFREE_DO_BODY(au_dfree.llist + AU_DFREE_KFREE, kfree);
124 AU_DFREE_DO_BODY(au_dfree.llist + AU_DFREE_FREE_PAGE, au_free_page);
125
126 #undef AU_CACHE_DFREE_DO_BODY
127 #undef AU_DFREE_DO_BODY
128 }
129
130 AU_CACHE_DFREE_FUNC(dinfo, DINFO, di_lnode);
131 AU_CACHE_DFREE_FUNC(icntnr, ICNTNR, lnode);
132 AU_CACHE_DFREE_FUNC(finfo, FINFO, fi_lnode);
133 AU_CACHE_DFREE_FUNC(vdir, VDIR, vd_lnode);
134 AU_CACHE_DFREE_FUNC(vdir_dehstr, DEHSTR, lnode);
135
136 static void au_cache_fin(void)
137 {
138 int i;
139 struct au_cache *cp;
140
141 /*
142 * Make sure all delayed rcu free inodes are flushed before we
143 * destroy cache.
144 */
145 rcu_barrier();
146
147 /* excluding AuCache_HNOTIFY */
148 BUILD_BUG_ON(AuCache_HNOTIFY + 1 != AuCache_Last);
149 flush_delayed_work(&au_dfree.dwork);
150 for (i = 0; i < AuCache_HNOTIFY; i++) {
151 cp = au_dfree.cache + i;
152 AuDebugOn(!llist_empty(&cp->llist));
153 kmem_cache_destroy(cp->cache);
154 cp->cache = NULL;
155 }
156 }
157
158 static int __init au_cache_init(void)
159 {
160 struct au_cache *cp;
161
162 cp = au_dfree.cache;
163 cp[AuCache_DINFO].cache = AuCacheCtor(au_dinfo, au_di_init_once);
164 if (cp[AuCache_DINFO].cache)
165 /* SLAB_DESTROY_BY_RCU */
166 cp[AuCache_ICNTNR].cache = AuCacheCtor(au_icntnr,
167 au_icntnr_init_once);
168 if (cp[AuCache_ICNTNR].cache)
169 cp[AuCache_FINFO].cache = AuCacheCtor(au_finfo,
170 au_fi_init_once);
171 if (cp[AuCache_FINFO].cache)
172 cp[AuCache_VDIR].cache = AuCache(au_vdir);
173 if (cp[AuCache_VDIR].cache)
174 cp[AuCache_DEHSTR].cache = AuCache(au_vdir_dehstr);
175 if (cp[AuCache_DEHSTR].cache)
176 return 0;
177
178 au_cache_fin();
179 return -ENOMEM;
180 }
181
182 /* ---------------------------------------------------------------------- */
183
184 int au_dir_roflags;
185
186 #ifdef CONFIG_AUFS_SBILIST
187 /*
188 * iterate_supers_type() doesn't protect us from
189 * remounting (branch management)
190 */
191 struct au_sphlhead au_sbilist;
192 #endif
193
194 /*
195 * functions for module interface.
196 */
197 MODULE_LICENSE("GPL");
198 /* MODULE_LICENSE("GPL v2"); */
199 MODULE_AUTHOR("Junjiro R. Okajima <aufs-users@lists.sourceforge.net>");
200 MODULE_DESCRIPTION(AUFS_NAME
201 " -- Advanced multi layered unification filesystem");
202 MODULE_VERSION(AUFS_VERSION);
203 MODULE_ALIAS_FS(AUFS_NAME);
204
205 /* this module parameter has no meaning when SYSFS is disabled */
206 int sysaufs_brs = 1;
207 MODULE_PARM_DESC(brs, "use <sysfs>/fs/aufs/si_*/brN");
208 module_param_named(brs, sysaufs_brs, int, S_IRUGO);
209
210 /* this module parameter has no meaning when USER_NS is disabled */
211 bool au_userns;
212 MODULE_PARM_DESC(allow_userns, "allow unprivileged to mount under userns");
213 module_param_named(allow_userns, au_userns, bool, S_IRUGO);
214
215 /* ---------------------------------------------------------------------- */
216
217 static char au_esc_chars[0x20 + 3]; /* 0x01-0x20, backslash, del, and NULL */
218
219 int au_seq_path(struct seq_file *seq, struct path *path)
220 {
221 int err;
222
223 err = seq_path(seq, path, au_esc_chars);
224 if (err > 0)
225 err = 0;
226 else if (err < 0)
227 err = -ENOMEM;
228
229 return err;
230 }
231
232 /* ---------------------------------------------------------------------- */
233
234 static int __init aufs_init(void)
235 {
236 int err, i;
237 char *p;
238 struct au_cache *cp;
239
240 p = au_esc_chars;
241 for (i = 1; i <= ' '; i++)
242 *p++ = i;
243 *p++ = '\\';
244 *p++ = '\x7f';
245 *p = 0;
246
247 au_dir_roflags = au_file_roflags(O_DIRECTORY | O_LARGEFILE);
248
249 memcpy(aufs_iop_nogetattr, aufs_iop, sizeof(aufs_iop));
250 for (i = 0; i < AuIop_Last; i++)
251 aufs_iop_nogetattr[i].getattr = NULL;
252
253 /* First, initialize au_dfree */
254 for (i = 0; i < AuCache_Last; i++) { /* including hnotify */
255 cp = au_dfree.cache + i;
256 cp->cache = NULL;
257 init_llist_head(&cp->llist);
258 }
259 for (i = 0; i < AU_DFREE_Last; i++)
260 init_llist_head(au_dfree.llist + i);
261 INIT_DELAYED_WORK(&au_dfree.dwork, au_do_dfree);
262
263 au_sbilist_init();
264 sysaufs_brs_init();
265 au_debug_init();
266 au_dy_init();
267 err = sysaufs_init();
268 if (unlikely(err))
269 goto out;
270 err = au_procfs_init();
271 if (unlikely(err))
272 goto out_sysaufs;
273 err = au_wkq_init();
274 if (unlikely(err))
275 goto out_procfs;
276 err = au_loopback_init();
277 if (unlikely(err))
278 goto out_wkq;
279 err = au_hnotify_init();
280 if (unlikely(err))
281 goto out_loopback;
282 err = au_sysrq_init();
283 if (unlikely(err))
284 goto out_hin;
285 err = au_cache_init();
286 if (unlikely(err))
287 goto out_sysrq;
288
289 aufs_fs_type.fs_flags |= au_userns ? FS_USERNS_MOUNT : 0;
290 err = register_filesystem(&aufs_fs_type);
291 if (unlikely(err))
292 goto out_cache;
293
294 /* since we define pr_fmt, call printk directly */
295 printk(KERN_INFO AUFS_NAME " " AUFS_VERSION "\n");
296 goto out; /* success */
297
298 out_cache:
299 au_cache_fin();
300 out_sysrq:
301 au_sysrq_fin();
302 out_hin:
303 au_hnotify_fin();
304 out_loopback:
305 au_loopback_fin();
306 out_wkq:
307 au_wkq_fin();
308 out_procfs:
309 au_procfs_fin();
310 out_sysaufs:
311 sysaufs_fin();
312 au_dy_fin();
313 flush_delayed_work(&au_dfree.dwork);
314 out:
315 return err;
316 }
317
318 static void __exit aufs_exit(void)
319 {
320 unregister_filesystem(&aufs_fs_type);
321 au_cache_fin();
322 au_sysrq_fin();
323 au_hnotify_fin();
324 au_loopback_fin();
325 au_wkq_fin();
326 au_procfs_fin();
327 sysaufs_fin();
328 au_dy_fin();
329 flush_delayed_work(&au_dfree.dwork);
330 }
331
332 module_init(aufs_init);
333 module_exit(aufs_exit);