]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blame - fs/aufs/dynop.c
Revert "UBUNTU: SAUCE: aufs -- Convert to use xattr handlers"
[mirror_ubuntu-zesty-kernel.git] / fs / aufs / dynop.c
CommitLineData
5b88fdd9
SF
1/*
2 * Copyright (C) 2010-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 * dynamically customizable operations for regular files
20 */
21
22#include "aufs.h"
23
24#define DyPrSym(key) AuDbgSym(key->dk_op.dy_hop)
25
26/*
27 * How large will these lists be?
28 * Usually just a few elements, 20-30 at most for each, I guess.
29 */
30static struct au_sphlhead dynop[AuDyLast];
31
32static struct au_dykey *dy_gfind_get(struct au_sphlhead *sphl, const void *h_op)
33{
34 struct au_dykey *key, *tmp;
35 struct hlist_head *head;
36
37 key = NULL;
38 head = &sphl->head;
39 rcu_read_lock();
40 hlist_for_each_entry_rcu(tmp, head, dk_hnode)
41 if (tmp->dk_op.dy_hop == h_op) {
42 key = tmp;
43 kref_get(&key->dk_kref);
44 break;
45 }
46 rcu_read_unlock();
47
48 return key;
49}
50
51static struct au_dykey *dy_bradd(struct au_branch *br, struct au_dykey *key)
52{
53 struct au_dykey **k, *found;
54 const void *h_op = key->dk_op.dy_hop;
55 int i;
56
57 found = NULL;
58 k = br->br_dykey;
59 for (i = 0; i < AuBrDynOp; i++)
60 if (k[i]) {
61 if (k[i]->dk_op.dy_hop == h_op) {
62 found = k[i];
63 break;
64 }
65 } else
66 break;
67 if (!found) {
68 spin_lock(&br->br_dykey_lock);
69 for (; i < AuBrDynOp; i++)
70 if (k[i]) {
71 if (k[i]->dk_op.dy_hop == h_op) {
72 found = k[i];
73 break;
74 }
75 } else {
76 k[i] = key;
77 break;
78 }
79 spin_unlock(&br->br_dykey_lock);
80 BUG_ON(i == AuBrDynOp); /* expand the array */
81 }
82
83 return found;
84}
85
86/* kref_get() if @key is already added */
87static struct au_dykey *dy_gadd(struct au_sphlhead *sphl, struct au_dykey *key)
88{
89 struct au_dykey *tmp, *found;
90 struct hlist_head *head;
91 const void *h_op = key->dk_op.dy_hop;
92
93 found = NULL;
94 head = &sphl->head;
95 spin_lock(&sphl->spin);
96 hlist_for_each_entry(tmp, head, dk_hnode)
97 if (tmp->dk_op.dy_hop == h_op) {
98 kref_get(&tmp->dk_kref);
99 found = tmp;
100 break;
101 }
102 if (!found)
103 hlist_add_head_rcu(&key->dk_hnode, head);
104 spin_unlock(&sphl->spin);
105
106 if (!found)
107 DyPrSym(key);
108 return found;
109}
110
111static void dy_free_rcu(struct rcu_head *rcu)
112{
113 struct au_dykey *key;
114
115 key = container_of(rcu, struct au_dykey, dk_rcu);
116 DyPrSym(key);
117 kfree(key); /* not delayed */
118}
119
120static void dy_free(struct kref *kref)
121{
122 struct au_dykey *key;
123 struct au_sphlhead *sphl;
124
125 key = container_of(kref, struct au_dykey, dk_kref);
126 sphl = dynop + key->dk_op.dy_type;
127 au_sphl_del_rcu(&key->dk_hnode, sphl);
128 call_rcu(&key->dk_rcu, dy_free_rcu);
129}
130
131void au_dy_put(struct au_dykey *key)
132{
133 kref_put(&key->dk_kref, dy_free);
134}
135
136/* ---------------------------------------------------------------------- */
137
138#define DyDbgSize(cnt, op) AuDebugOn(cnt != sizeof(op)/sizeof(void *))
139
140#ifdef CONFIG_AUFS_DEBUG
141#define DyDbgDeclare(cnt) unsigned int cnt = 0
142#define DyDbgInc(cnt) do { cnt++; } while (0)
143#else
144#define DyDbgDeclare(cnt) do {} while (0)
145#define DyDbgInc(cnt) do {} while (0)
146#endif
147
148#define DySet(func, dst, src, h_op, h_sb) do { \
149 DyDbgInc(cnt); \
150 if (h_op->func) { \
151 if (src.func) \
152 dst.func = src.func; \
153 else \
154 AuDbg("%s %s\n", au_sbtype(h_sb), #func); \
155 } \
156} while (0)
157
158#define DySetForce(func, dst, src) do { \
159 AuDebugOn(!src.func); \
160 DyDbgInc(cnt); \
161 dst.func = src.func; \
162} while (0)
163
164#define DySetAop(func) \
165 DySet(func, dyaop->da_op, aufs_aop, h_aop, h_sb)
166#define DySetAopForce(func) \
167 DySetForce(func, dyaop->da_op, aufs_aop)
168
169static void dy_aop(struct au_dykey *key, const void *h_op,
170 struct super_block *h_sb __maybe_unused)
171{
172 struct au_dyaop *dyaop = (void *)key;
173 const struct address_space_operations *h_aop = h_op;
174 DyDbgDeclare(cnt);
175
176 AuDbg("%s\n", au_sbtype(h_sb));
177
178 DySetAop(writepage);
179 DySetAopForce(readpage); /* force */
180 DySetAop(writepages);
181 DySetAop(set_page_dirty);
182 DySetAop(readpages);
183 DySetAop(write_begin);
184 DySetAop(write_end);
185 DySetAop(bmap);
186 DySetAop(invalidatepage);
187 DySetAop(releasepage);
188 DySetAop(freepage);
189 /* this one will be changed according to an aufs mount option */
190 DySetAop(direct_IO);
191 DySetAop(migratepage);
192 DySetAop(isolate_page);
193 DySetAop(putback_page);
194 DySetAop(launder_page);
195 DySetAop(is_partially_uptodate);
196 DySetAop(is_dirty_writeback);
197 DySetAop(error_remove_page);
198 DySetAop(swap_activate);
199 DySetAop(swap_deactivate);
200
201 DyDbgSize(cnt, *h_aop);
202}
203
204/* ---------------------------------------------------------------------- */
205
206static void dy_bug(struct kref *kref)
207{
208 BUG();
209}
210
211static struct au_dykey *dy_get(struct au_dynop *op, struct au_branch *br)
212{
213 struct au_dykey *key, *old;
214 struct au_sphlhead *sphl;
215 struct op {
216 unsigned int sz;
217 void (*set)(struct au_dykey *key, const void *h_op,
218 struct super_block *h_sb __maybe_unused);
219 };
220 static const struct op a[] = {
221 [AuDy_AOP] = {
222 .sz = sizeof(struct au_dyaop),
223 .set = dy_aop
224 }
225 };
226 const struct op *p;
227
228 sphl = dynop + op->dy_type;
229 key = dy_gfind_get(sphl, op->dy_hop);
230 if (key)
231 goto out_add; /* success */
232
233 p = a + op->dy_type;
234 key = kzalloc(p->sz, GFP_NOFS);
235 if (unlikely(!key)) {
236 key = ERR_PTR(-ENOMEM);
237 goto out;
238 }
239
240 key->dk_op.dy_hop = op->dy_hop;
241 kref_init(&key->dk_kref);
242 p->set(key, op->dy_hop, au_br_sb(br));
243 old = dy_gadd(sphl, key);
244 if (old) {
245 au_delayed_kfree(key);
246 key = old;
247 }
248
249out_add:
250 old = dy_bradd(br, key);
251 if (old)
252 /* its ref-count should never be zero here */
253 kref_put(&key->dk_kref, dy_bug);
254out:
255 return key;
256}
257
258/* ---------------------------------------------------------------------- */
259/*
260 * Aufs prohibits O_DIRECT by defaut even if the branch supports it.
261 * This behaviour is necessary to return an error from open(O_DIRECT) instead
262 * of the succeeding I/O. The dio mount option enables O_DIRECT and makes
263 * open(O_DIRECT) always succeed, but the succeeding I/O may return an error.
264 * See the aufs manual in detail.
265 */
266static void dy_adx(struct au_dyaop *dyaop, int do_dx)
267{
268 if (!do_dx)
269 dyaop->da_op.direct_IO = NULL;
270 else
271 dyaop->da_op.direct_IO = aufs_aop.direct_IO;
272}
273
274static struct au_dyaop *dy_aget(struct au_branch *br,
275 const struct address_space_operations *h_aop,
276 int do_dx)
277{
278 struct au_dyaop *dyaop;
279 struct au_dynop op;
280
281 op.dy_type = AuDy_AOP;
282 op.dy_haop = h_aop;
283 dyaop = (void *)dy_get(&op, br);
284 if (IS_ERR(dyaop))
285 goto out;
286 dy_adx(dyaop, do_dx);
287
288out:
289 return dyaop;
290}
291
292int au_dy_iaop(struct inode *inode, aufs_bindex_t bindex,
293 struct inode *h_inode)
294{
295 int err, do_dx;
296 struct super_block *sb;
297 struct au_branch *br;
298 struct au_dyaop *dyaop;
299
300 AuDebugOn(!S_ISREG(h_inode->i_mode));
301 IiMustWriteLock(inode);
302
303 sb = inode->i_sb;
304 br = au_sbr(sb, bindex);
305 do_dx = !!au_opt_test(au_mntflags(sb), DIO);
306 dyaop = dy_aget(br, h_inode->i_mapping->a_ops, do_dx);
307 err = PTR_ERR(dyaop);
308 if (IS_ERR(dyaop))
309 /* unnecessary to call dy_fput() */
310 goto out;
311
312 err = 0;
313 inode->i_mapping->a_ops = &dyaop->da_op;
314
315out:
316 return err;
317}
318
319/*
320 * Is it safe to replace a_ops during the inode/file is in operation?
321 * Yes, I hope so.
322 */
323int au_dy_irefresh(struct inode *inode)
324{
325 int err;
326 aufs_bindex_t btop;
327 struct inode *h_inode;
328
329 err = 0;
330 if (S_ISREG(inode->i_mode)) {
331 btop = au_ibtop(inode);
332 h_inode = au_h_iptr(inode, btop);
333 err = au_dy_iaop(inode, btop, h_inode);
334 }
335 return err;
336}
337
338void au_dy_arefresh(int do_dx)
339{
340 struct au_sphlhead *sphl;
341 struct hlist_head *head;
342 struct au_dykey *key;
343
344 sphl = dynop + AuDy_AOP;
345 head = &sphl->head;
346 spin_lock(&sphl->spin);
347 hlist_for_each_entry(key, head, dk_hnode)
348 dy_adx((void *)key, do_dx);
349 spin_unlock(&sphl->spin);
350}
351
352/* ---------------------------------------------------------------------- */
353
354void __init au_dy_init(void)
355{
356 int i;
357
358 /* make sure that 'struct au_dykey *' can be any type */
359 BUILD_BUG_ON(offsetof(struct au_dyaop, da_key));
360
361 for (i = 0; i < AuDyLast; i++)
362 au_sphl_init(dynop + i);
363}
364
365void au_dy_fin(void)
366{
367 int i;
368
369 for (i = 0; i < AuDyLast; i++)
370 WARN_ON(!hlist_empty(&dynop[i].head));
371}