]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blame - 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
CommitLineData
e14748e8
SF
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 */
27void *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
68out:
69 return p;
70}
71
72void *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
86struct au_dfree au_dfree;
87
88/* delayed free */
89static 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
130AU_CACHE_DFREE_FUNC(dinfo, DINFO, di_lnode);
131AU_CACHE_DFREE_FUNC(icntnr, ICNTNR, lnode);
132AU_CACHE_DFREE_FUNC(finfo, FINFO, fi_lnode);
133AU_CACHE_DFREE_FUNC(vdir, VDIR, vd_lnode);
134AU_CACHE_DFREE_FUNC(vdir_dehstr, DEHSTR, lnode);
135
136static 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
158static 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
184int au_dir_roflags;
185
186#ifdef CONFIG_AUFS_SBILIST
187/*
188 * iterate_supers_type() doesn't protect us from
189 * remounting (branch management)
190 */
191struct au_sphlhead au_sbilist;
192#endif
193
194/*
195 * functions for module interface.
196 */
197MODULE_LICENSE("GPL");
198/* MODULE_LICENSE("GPL v2"); */
199MODULE_AUTHOR("Junjiro R. Okajima <aufs-users@lists.sourceforge.net>");
200MODULE_DESCRIPTION(AUFS_NAME
201 " -- Advanced multi layered unification filesystem");
202MODULE_VERSION(AUFS_VERSION);
203MODULE_ALIAS_FS(AUFS_NAME);
204
205/* this module parameter has no meaning when SYSFS is disabled */
206int sysaufs_brs = 1;
207MODULE_PARM_DESC(brs, "use <sysfs>/fs/aufs/si_*/brN");
208module_param_named(brs, sysaufs_brs, int, S_IRUGO);
209
210/* this module parameter has no meaning when USER_NS is disabled */
211bool au_userns;
212MODULE_PARM_DESC(allow_userns, "allow unprivileged to mount under userns");
213module_param_named(allow_userns, au_userns, bool, S_IRUGO);
214
215/* ---------------------------------------------------------------------- */
216
217static char au_esc_chars[0x20 + 3]; /* 0x01-0x20, backslash, del, and NULL */
218
219int 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
234static 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
298out_cache:
299 au_cache_fin();
300out_sysrq:
301 au_sysrq_fin();
302out_hin:
303 au_hnotify_fin();
304out_loopback:
305 au_loopback_fin();
306out_wkq:
307 au_wkq_fin();
308out_procfs:
309 au_procfs_fin();
310out_sysaufs:
311 sysaufs_fin();
312 au_dy_fin();
313 flush_delayed_work(&au_dfree.dwork);
314out:
315 return err;
316}
317
318static 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
332module_init(aufs_init);
333module_exit(aufs_exit);