]>
Commit | Line | Data |
---|---|---|
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 | * dentry private data | |
20 | */ | |
21 | ||
22 | #include "aufs.h" | |
23 | ||
24 | void au_di_init_once(void *_dinfo) | |
25 | { | |
26 | struct au_dinfo *dinfo = _dinfo; | |
27 | ||
28 | au_rw_init(&dinfo->di_rwsem); | |
29 | } | |
30 | ||
31 | struct au_dinfo *au_di_alloc(struct super_block *sb, unsigned int lsc) | |
32 | { | |
33 | struct au_dinfo *dinfo; | |
34 | int nbr, i; | |
35 | ||
36 | dinfo = au_cache_alloc_dinfo(); | |
37 | if (unlikely(!dinfo)) | |
38 | goto out; | |
39 | ||
40 | nbr = au_sbbot(sb) + 1; | |
41 | if (nbr <= 0) | |
42 | nbr = 1; | |
43 | dinfo->di_hdentry = kcalloc(nbr, sizeof(*dinfo->di_hdentry), GFP_NOFS); | |
44 | if (dinfo->di_hdentry) { | |
45 | au_rw_write_lock_nested(&dinfo->di_rwsem, lsc); | |
46 | dinfo->di_btop = -1; | |
47 | dinfo->di_bbot = -1; | |
48 | dinfo->di_bwh = -1; | |
49 | dinfo->di_bdiropq = -1; | |
50 | dinfo->di_tmpfile = 0; | |
51 | for (i = 0; i < nbr; i++) | |
52 | dinfo->di_hdentry[i].hd_id = -1; | |
53 | goto out; | |
54 | } | |
55 | ||
56 | au_cache_dfree_dinfo(dinfo); | |
57 | dinfo = NULL; | |
58 | ||
59 | out: | |
60 | return dinfo; | |
61 | } | |
62 | ||
63 | void au_di_free(struct au_dinfo *dinfo) | |
64 | { | |
65 | struct au_hdentry *p; | |
66 | aufs_bindex_t bbot, bindex; | |
67 | ||
68 | /* dentry may not be revalidated */ | |
69 | bindex = dinfo->di_btop; | |
70 | if (bindex >= 0) { | |
71 | bbot = dinfo->di_bbot; | |
72 | p = au_hdentry(dinfo, bindex); | |
73 | while (bindex++ <= bbot) | |
74 | au_hdput(p++); | |
75 | } | |
76 | au_delayed_kfree(dinfo->di_hdentry); | |
77 | au_cache_dfree_dinfo(dinfo); | |
78 | } | |
79 | ||
80 | void au_di_swap(struct au_dinfo *a, struct au_dinfo *b) | |
81 | { | |
82 | struct au_hdentry *p; | |
83 | aufs_bindex_t bi; | |
84 | ||
85 | AuRwMustWriteLock(&a->di_rwsem); | |
86 | AuRwMustWriteLock(&b->di_rwsem); | |
87 | ||
88 | #define DiSwap(v, name) \ | |
89 | do { \ | |
90 | v = a->di_##name; \ | |
91 | a->di_##name = b->di_##name; \ | |
92 | b->di_##name = v; \ | |
93 | } while (0) | |
94 | ||
95 | DiSwap(p, hdentry); | |
96 | DiSwap(bi, btop); | |
97 | DiSwap(bi, bbot); | |
98 | DiSwap(bi, bwh); | |
99 | DiSwap(bi, bdiropq); | |
100 | /* smp_mb(); */ | |
101 | ||
102 | #undef DiSwap | |
103 | } | |
104 | ||
105 | void au_di_cp(struct au_dinfo *dst, struct au_dinfo *src) | |
106 | { | |
107 | AuRwMustWriteLock(&dst->di_rwsem); | |
108 | AuRwMustWriteLock(&src->di_rwsem); | |
109 | ||
110 | dst->di_btop = src->di_btop; | |
111 | dst->di_bbot = src->di_bbot; | |
112 | dst->di_bwh = src->di_bwh; | |
113 | dst->di_bdiropq = src->di_bdiropq; | |
114 | /* smp_mb(); */ | |
115 | } | |
116 | ||
117 | int au_di_init(struct dentry *dentry) | |
118 | { | |
119 | int err; | |
120 | struct super_block *sb; | |
121 | struct au_dinfo *dinfo; | |
122 | ||
123 | err = 0; | |
124 | sb = dentry->d_sb; | |
125 | dinfo = au_di_alloc(sb, AuLsc_DI_CHILD); | |
126 | if (dinfo) { | |
127 | atomic_set(&dinfo->di_generation, au_sigen(sb)); | |
128 | /* smp_mb(); */ /* atomic_set */ | |
129 | dentry->d_fsdata = dinfo; | |
130 | } else | |
131 | err = -ENOMEM; | |
132 | ||
133 | return err; | |
134 | } | |
135 | ||
136 | void au_di_fin(struct dentry *dentry) | |
137 | { | |
138 | struct au_dinfo *dinfo; | |
139 | ||
140 | dinfo = au_di(dentry); | |
141 | AuRwDestroy(&dinfo->di_rwsem); | |
142 | au_di_free(dinfo); | |
143 | } | |
144 | ||
145 | int au_di_realloc(struct au_dinfo *dinfo, int nbr, int may_shrink) | |
146 | { | |
147 | int err, sz; | |
148 | struct au_hdentry *hdp; | |
149 | ||
150 | AuRwMustWriteLock(&dinfo->di_rwsem); | |
151 | ||
152 | err = -ENOMEM; | |
153 | sz = sizeof(*hdp) * (dinfo->di_bbot + 1); | |
154 | if (!sz) | |
155 | sz = sizeof(*hdp); | |
156 | hdp = au_kzrealloc(dinfo->di_hdentry, sz, sizeof(*hdp) * nbr, GFP_NOFS, | |
157 | may_shrink); | |
158 | if (hdp) { | |
159 | dinfo->di_hdentry = hdp; | |
160 | err = 0; | |
161 | } | |
162 | ||
163 | return err; | |
164 | } | |
165 | ||
166 | /* ---------------------------------------------------------------------- */ | |
167 | ||
168 | static void do_ii_write_lock(struct inode *inode, unsigned int lsc) | |
169 | { | |
170 | switch (lsc) { | |
171 | case AuLsc_DI_CHILD: | |
172 | ii_write_lock_child(inode); | |
173 | break; | |
174 | case AuLsc_DI_CHILD2: | |
175 | ii_write_lock_child2(inode); | |
176 | break; | |
177 | case AuLsc_DI_CHILD3: | |
178 | ii_write_lock_child3(inode); | |
179 | break; | |
180 | case AuLsc_DI_PARENT: | |
181 | ii_write_lock_parent(inode); | |
182 | break; | |
183 | case AuLsc_DI_PARENT2: | |
184 | ii_write_lock_parent2(inode); | |
185 | break; | |
186 | case AuLsc_DI_PARENT3: | |
187 | ii_write_lock_parent3(inode); | |
188 | break; | |
189 | default: | |
190 | BUG(); | |
191 | } | |
192 | } | |
193 | ||
194 | static void do_ii_read_lock(struct inode *inode, unsigned int lsc) | |
195 | { | |
196 | switch (lsc) { | |
197 | case AuLsc_DI_CHILD: | |
198 | ii_read_lock_child(inode); | |
199 | break; | |
200 | case AuLsc_DI_CHILD2: | |
201 | ii_read_lock_child2(inode); | |
202 | break; | |
203 | case AuLsc_DI_CHILD3: | |
204 | ii_read_lock_child3(inode); | |
205 | break; | |
206 | case AuLsc_DI_PARENT: | |
207 | ii_read_lock_parent(inode); | |
208 | break; | |
209 | case AuLsc_DI_PARENT2: | |
210 | ii_read_lock_parent2(inode); | |
211 | break; | |
212 | case AuLsc_DI_PARENT3: | |
213 | ii_read_lock_parent3(inode); | |
214 | break; | |
215 | default: | |
216 | BUG(); | |
217 | } | |
218 | } | |
219 | ||
220 | void di_read_lock(struct dentry *d, int flags, unsigned int lsc) | |
221 | { | |
222 | struct inode *inode; | |
223 | ||
224 | au_rw_read_lock_nested(&au_di(d)->di_rwsem, lsc); | |
225 | if (d_really_is_positive(d)) { | |
226 | inode = d_inode(d); | |
227 | if (au_ftest_lock(flags, IW)) | |
228 | do_ii_write_lock(inode, lsc); | |
229 | else if (au_ftest_lock(flags, IR)) | |
230 | do_ii_read_lock(inode, lsc); | |
231 | } | |
232 | } | |
233 | ||
234 | void di_read_unlock(struct dentry *d, int flags) | |
235 | { | |
236 | struct inode *inode; | |
237 | ||
238 | if (d_really_is_positive(d)) { | |
239 | inode = d_inode(d); | |
240 | if (au_ftest_lock(flags, IW)) { | |
241 | au_dbg_verify_dinode(d); | |
242 | ii_write_unlock(inode); | |
243 | } else if (au_ftest_lock(flags, IR)) { | |
244 | au_dbg_verify_dinode(d); | |
245 | ii_read_unlock(inode); | |
246 | } | |
247 | } | |
248 | au_rw_read_unlock(&au_di(d)->di_rwsem); | |
249 | } | |
250 | ||
251 | void di_downgrade_lock(struct dentry *d, int flags) | |
252 | { | |
253 | if (d_really_is_positive(d) && au_ftest_lock(flags, IR)) | |
254 | ii_downgrade_lock(d_inode(d)); | |
255 | au_rw_dgrade_lock(&au_di(d)->di_rwsem); | |
256 | } | |
257 | ||
258 | void di_write_lock(struct dentry *d, unsigned int lsc) | |
259 | { | |
260 | au_rw_write_lock_nested(&au_di(d)->di_rwsem, lsc); | |
261 | if (d_really_is_positive(d)) | |
262 | do_ii_write_lock(d_inode(d), lsc); | |
263 | } | |
264 | ||
265 | void di_write_unlock(struct dentry *d) | |
266 | { | |
267 | au_dbg_verify_dinode(d); | |
268 | if (d_really_is_positive(d)) | |
269 | ii_write_unlock(d_inode(d)); | |
270 | au_rw_write_unlock(&au_di(d)->di_rwsem); | |
271 | } | |
272 | ||
273 | void di_write_lock2_child(struct dentry *d1, struct dentry *d2, int isdir) | |
274 | { | |
275 | AuDebugOn(d1 == d2 | |
276 | || d_inode(d1) == d_inode(d2) | |
277 | || d1->d_sb != d2->d_sb); | |
278 | ||
279 | if (isdir && au_test_subdir(d1, d2)) { | |
280 | di_write_lock_child(d1); | |
281 | di_write_lock_child2(d2); | |
282 | } else { | |
283 | /* there should be no races */ | |
284 | di_write_lock_child(d2); | |
285 | di_write_lock_child2(d1); | |
286 | } | |
287 | } | |
288 | ||
289 | void di_write_lock2_parent(struct dentry *d1, struct dentry *d2, int isdir) | |
290 | { | |
291 | AuDebugOn(d1 == d2 | |
292 | || d_inode(d1) == d_inode(d2) | |
293 | || d1->d_sb != d2->d_sb); | |
294 | ||
295 | if (isdir && au_test_subdir(d1, d2)) { | |
296 | di_write_lock_parent(d1); | |
297 | di_write_lock_parent2(d2); | |
298 | } else { | |
299 | /* there should be no races */ | |
300 | di_write_lock_parent(d2); | |
301 | di_write_lock_parent2(d1); | |
302 | } | |
303 | } | |
304 | ||
305 | void di_write_unlock2(struct dentry *d1, struct dentry *d2) | |
306 | { | |
307 | di_write_unlock(d1); | |
308 | if (d_inode(d1) == d_inode(d2)) | |
309 | au_rw_write_unlock(&au_di(d2)->di_rwsem); | |
310 | else | |
311 | di_write_unlock(d2); | |
312 | } | |
313 | ||
314 | /* ---------------------------------------------------------------------- */ | |
315 | ||
316 | struct dentry *au_h_dptr(struct dentry *dentry, aufs_bindex_t bindex) | |
317 | { | |
318 | struct dentry *d; | |
319 | ||
320 | DiMustAnyLock(dentry); | |
321 | ||
322 | if (au_dbtop(dentry) < 0 || bindex < au_dbtop(dentry)) | |
323 | return NULL; | |
324 | AuDebugOn(bindex < 0); | |
325 | d = au_hdentry(au_di(dentry), bindex)->hd_dentry; | |
326 | AuDebugOn(d && au_dcount(d) <= 0); | |
327 | return d; | |
328 | } | |
329 | ||
330 | /* | |
331 | * extended version of au_h_dptr(). | |
332 | * returns a hashed and positive (or linkable) h_dentry in bindex, NULL, or | |
333 | * error. | |
334 | */ | |
335 | struct dentry *au_h_d_alias(struct dentry *dentry, aufs_bindex_t bindex) | |
336 | { | |
337 | struct dentry *h_dentry; | |
338 | struct inode *inode, *h_inode; | |
339 | ||
340 | AuDebugOn(d_really_is_negative(dentry)); | |
341 | ||
342 | h_dentry = NULL; | |
343 | if (au_dbtop(dentry) <= bindex | |
344 | && bindex <= au_dbbot(dentry)) | |
345 | h_dentry = au_h_dptr(dentry, bindex); | |
346 | if (h_dentry && !au_d_linkable(h_dentry)) { | |
347 | dget(h_dentry); | |
348 | goto out; /* success */ | |
349 | } | |
350 | ||
351 | inode = d_inode(dentry); | |
352 | AuDebugOn(bindex < au_ibtop(inode)); | |
353 | AuDebugOn(au_ibbot(inode) < bindex); | |
354 | h_inode = au_h_iptr(inode, bindex); | |
355 | h_dentry = d_find_alias(h_inode); | |
356 | if (h_dentry) { | |
357 | if (!IS_ERR(h_dentry)) { | |
358 | if (!au_d_linkable(h_dentry)) | |
359 | goto out; /* success */ | |
360 | dput(h_dentry); | |
361 | } else | |
362 | goto out; | |
363 | } | |
364 | ||
365 | if (au_opt_test(au_mntflags(dentry->d_sb), PLINK)) { | |
366 | h_dentry = au_plink_lkup(inode, bindex); | |
367 | AuDebugOn(!h_dentry); | |
368 | if (!IS_ERR(h_dentry)) { | |
369 | if (!au_d_hashed_positive(h_dentry)) | |
370 | goto out; /* success */ | |
371 | dput(h_dentry); | |
372 | h_dentry = NULL; | |
373 | } | |
374 | } | |
375 | ||
376 | out: | |
377 | AuDbgDentry(h_dentry); | |
378 | return h_dentry; | |
379 | } | |
380 | ||
381 | aufs_bindex_t au_dbtail(struct dentry *dentry) | |
382 | { | |
383 | aufs_bindex_t bbot, bwh; | |
384 | ||
385 | bbot = au_dbbot(dentry); | |
386 | if (0 <= bbot) { | |
387 | bwh = au_dbwh(dentry); | |
388 | if (!bwh) | |
389 | return bwh; | |
390 | if (0 < bwh && bwh < bbot) | |
391 | return bwh - 1; | |
392 | } | |
393 | return bbot; | |
394 | } | |
395 | ||
396 | aufs_bindex_t au_dbtaildir(struct dentry *dentry) | |
397 | { | |
398 | aufs_bindex_t bbot, bopq; | |
399 | ||
400 | bbot = au_dbtail(dentry); | |
401 | if (0 <= bbot) { | |
402 | bopq = au_dbdiropq(dentry); | |
403 | if (0 <= bopq && bopq < bbot) | |
404 | bbot = bopq; | |
405 | } | |
406 | return bbot; | |
407 | } | |
408 | ||
409 | /* ---------------------------------------------------------------------- */ | |
410 | ||
411 | void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex, | |
412 | struct dentry *h_dentry) | |
413 | { | |
414 | struct au_dinfo *dinfo; | |
415 | struct au_hdentry *hd; | |
416 | struct au_branch *br; | |
417 | ||
418 | DiMustWriteLock(dentry); | |
419 | ||
420 | dinfo = au_di(dentry); | |
421 | hd = au_hdentry(dinfo, bindex); | |
422 | au_hdput(hd); | |
423 | hd->hd_dentry = h_dentry; | |
424 | if (h_dentry) { | |
425 | br = au_sbr(dentry->d_sb, bindex); | |
426 | hd->hd_id = br->br_id; | |
427 | } | |
428 | } | |
429 | ||
430 | int au_dbrange_test(struct dentry *dentry) | |
431 | { | |
432 | int err; | |
433 | aufs_bindex_t btop, bbot; | |
434 | ||
435 | err = 0; | |
436 | btop = au_dbtop(dentry); | |
437 | bbot = au_dbbot(dentry); | |
438 | if (btop >= 0) | |
439 | AuDebugOn(bbot < 0 && btop > bbot); | |
440 | else { | |
441 | err = -EIO; | |
442 | AuDebugOn(bbot >= 0); | |
443 | } | |
444 | ||
445 | return err; | |
446 | } | |
447 | ||
448 | int au_digen_test(struct dentry *dentry, unsigned int sigen) | |
449 | { | |
450 | int err; | |
451 | ||
452 | err = 0; | |
453 | if (unlikely(au_digen(dentry) != sigen | |
454 | || au_iigen_test(d_inode(dentry), sigen))) | |
455 | err = -EIO; | |
456 | ||
457 | return err; | |
458 | } | |
459 | ||
460 | void au_update_digen(struct dentry *dentry) | |
461 | { | |
462 | atomic_set(&au_di(dentry)->di_generation, au_sigen(dentry->d_sb)); | |
463 | /* smp_mb(); */ /* atomic_set */ | |
464 | } | |
465 | ||
466 | void au_update_dbrange(struct dentry *dentry, int do_put_zero) | |
467 | { | |
468 | struct au_dinfo *dinfo; | |
469 | struct dentry *h_d; | |
470 | struct au_hdentry *hdp; | |
471 | aufs_bindex_t bindex, bbot; | |
472 | ||
473 | DiMustWriteLock(dentry); | |
474 | ||
475 | dinfo = au_di(dentry); | |
476 | if (!dinfo || dinfo->di_btop < 0) | |
477 | return; | |
478 | ||
479 | if (do_put_zero) { | |
480 | bbot = dinfo->di_bbot; | |
481 | bindex = dinfo->di_btop; | |
482 | hdp = au_hdentry(dinfo, bindex); | |
483 | for (; bindex <= bbot; bindex++, hdp++) { | |
484 | h_d = hdp->hd_dentry; | |
485 | if (h_d && d_is_negative(h_d)) | |
486 | au_set_h_dptr(dentry, bindex, NULL); | |
487 | } | |
488 | } | |
489 | ||
490 | dinfo->di_btop = 0; | |
491 | hdp = au_hdentry(dinfo, dinfo->di_btop); | |
492 | for (; dinfo->di_btop <= dinfo->di_bbot; dinfo->di_btop++, hdp++) | |
493 | if (hdp->hd_dentry) | |
494 | break; | |
495 | if (dinfo->di_btop > dinfo->di_bbot) { | |
496 | dinfo->di_btop = -1; | |
497 | dinfo->di_bbot = -1; | |
498 | return; | |
499 | } | |
500 | ||
501 | hdp = au_hdentry(dinfo, dinfo->di_bbot); | |
502 | for (; dinfo->di_bbot >= 0; dinfo->di_bbot--, hdp--) | |
503 | if (hdp->hd_dentry) | |
504 | break; | |
505 | AuDebugOn(dinfo->di_btop > dinfo->di_bbot || dinfo->di_bbot < 0); | |
506 | } | |
507 | ||
508 | void au_update_dbtop(struct dentry *dentry) | |
509 | { | |
510 | aufs_bindex_t bindex, bbot; | |
511 | struct dentry *h_dentry; | |
512 | ||
513 | bbot = au_dbbot(dentry); | |
514 | for (bindex = au_dbtop(dentry); bindex <= bbot; bindex++) { | |
515 | h_dentry = au_h_dptr(dentry, bindex); | |
516 | if (!h_dentry) | |
517 | continue; | |
518 | if (d_is_positive(h_dentry)) { | |
519 | au_set_dbtop(dentry, bindex); | |
520 | return; | |
521 | } | |
522 | au_set_h_dptr(dentry, bindex, NULL); | |
523 | } | |
524 | } | |
525 | ||
526 | void au_update_dbbot(struct dentry *dentry) | |
527 | { | |
528 | aufs_bindex_t bindex, btop; | |
529 | struct dentry *h_dentry; | |
530 | ||
531 | btop = au_dbtop(dentry); | |
532 | for (bindex = au_dbbot(dentry); bindex >= btop; bindex--) { | |
533 | h_dentry = au_h_dptr(dentry, bindex); | |
534 | if (!h_dentry) | |
535 | continue; | |
536 | if (d_is_positive(h_dentry)) { | |
537 | au_set_dbbot(dentry, bindex); | |
538 | return; | |
539 | } | |
540 | au_set_h_dptr(dentry, bindex, NULL); | |
541 | } | |
542 | } | |
543 | ||
544 | int au_find_dbindex(struct dentry *dentry, struct dentry *h_dentry) | |
545 | { | |
546 | aufs_bindex_t bindex, bbot; | |
547 | ||
548 | bbot = au_dbbot(dentry); | |
549 | for (bindex = au_dbtop(dentry); bindex <= bbot; bindex++) | |
550 | if (au_h_dptr(dentry, bindex) == h_dentry) | |
551 | return bindex; | |
552 | return -1; | |
553 | } |