Merge branch 'stable-3.2' into pandora-3.2
[pandora-kernel.git] / fs / aufs / vdir.c
1 /*
2  * Copyright (C) 2005-2013 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, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18
19 /*
20  * virtual or vertical directory
21  */
22
23 #include "aufs.h"
24
25 static unsigned int calc_size(int nlen)
26 {
27         return ALIGN(sizeof(struct au_vdir_de) + nlen, sizeof(ino_t));
28 }
29
30 static int set_deblk_end(union au_vdir_deblk_p *p,
31                          union au_vdir_deblk_p *deblk_end)
32 {
33         if (calc_size(0) <= deblk_end->deblk - p->deblk) {
34                 p->de->de_str.len = 0;
35                 /* smp_mb(); */
36                 return 0;
37         }
38         return -1; /* error */
39 }
40
41 /* returns true or false */
42 static int is_deblk_end(union au_vdir_deblk_p *p,
43                         union au_vdir_deblk_p *deblk_end)
44 {
45         if (calc_size(0) <= deblk_end->deblk - p->deblk)
46                 return !p->de->de_str.len;
47         return 1;
48 }
49
50 static unsigned char *last_deblk(struct au_vdir *vdir)
51 {
52         return vdir->vd_deblk[vdir->vd_nblk - 1];
53 }
54
55 /* ---------------------------------------------------------------------- */
56
57 /* estimate the apropriate size for name hash table */
58 unsigned int au_rdhash_est(loff_t sz)
59 {
60         unsigned int n;
61
62         n = UINT_MAX;
63         sz >>= 10;
64         if (sz < n)
65                 n = sz;
66         if (sz < AUFS_RDHASH_DEF)
67                 n = AUFS_RDHASH_DEF;
68         /* pr_info("n %u\n", n); */
69         return n;
70 }
71
72 /*
73  * the allocated memory has to be freed by
74  * au_nhash_wh_free() or au_nhash_de_free().
75  */
76 int au_nhash_alloc(struct au_nhash *nhash, unsigned int num_hash, gfp_t gfp)
77 {
78         struct hlist_head *head;
79         unsigned int u;
80
81         head = kmalloc(sizeof(*nhash->nh_head) * num_hash, gfp);
82         if (head) {
83                 nhash->nh_num = num_hash;
84                 nhash->nh_head = head;
85                 for (u = 0; u < num_hash; u++)
86                         INIT_HLIST_HEAD(head++);
87                 return 0; /* success */
88         }
89
90         return -ENOMEM;
91 }
92
93 static void nhash_count(struct hlist_head *head)
94 {
95 #if 0
96         unsigned long n;
97         struct hlist_node *pos;
98
99         n = 0;
100         hlist_for_each(pos, head)
101                 n++;
102         pr_info("%lu\n", n);
103 #endif
104 }
105
106 static void au_nhash_wh_do_free(struct hlist_head *head)
107 {
108         struct au_vdir_wh *tpos;
109         struct hlist_node *pos, *node;
110
111         hlist_for_each_entry_safe(tpos, pos, node, head, wh_hash) {
112                 /* hlist_del(pos); */
113                 kfree(tpos);
114         }
115 }
116
117 static void au_nhash_de_do_free(struct hlist_head *head)
118 {
119         struct au_vdir_dehstr *tpos;
120         struct hlist_node *pos, *node;
121
122         hlist_for_each_entry_safe(tpos, pos, node, head, hash) {
123                 /* hlist_del(pos); */
124                 au_cache_free_vdir_dehstr(tpos);
125         }
126 }
127
128 static void au_nhash_do_free(struct au_nhash *nhash,
129                              void (*free)(struct hlist_head *head))
130 {
131         unsigned int n;
132         struct hlist_head *head;
133
134         n = nhash->nh_num;
135         if (!n)
136                 return;
137
138         head = nhash->nh_head;
139         while (n-- > 0) {
140                 nhash_count(head);
141                 free(head++);
142         }
143         kfree(nhash->nh_head);
144 }
145
146 void au_nhash_wh_free(struct au_nhash *whlist)
147 {
148         au_nhash_do_free(whlist, au_nhash_wh_do_free);
149 }
150
151 static void au_nhash_de_free(struct au_nhash *delist)
152 {
153         au_nhash_do_free(delist, au_nhash_de_do_free);
154 }
155
156 /* ---------------------------------------------------------------------- */
157
158 int au_nhash_test_longer_wh(struct au_nhash *whlist, aufs_bindex_t btgt,
159                             int limit)
160 {
161         int num;
162         unsigned int u, n;
163         struct hlist_head *head;
164         struct au_vdir_wh *tpos;
165         struct hlist_node *pos;
166
167         num = 0;
168         n = whlist->nh_num;
169         head = whlist->nh_head;
170         for (u = 0; u < n; u++, head++)
171                 hlist_for_each_entry(tpos, pos, head, wh_hash)
172                         if (tpos->wh_bindex == btgt && ++num > limit)
173                                 return 1;
174         return 0;
175 }
176
177 static struct hlist_head *au_name_hash(struct au_nhash *nhash,
178                                        unsigned char *name,
179                                        unsigned int len)
180 {
181         unsigned int v;
182         /* const unsigned int magic_bit = 12; */
183
184         AuDebugOn(!nhash->nh_num || !nhash->nh_head);
185
186         v = 0;
187         while (len--)
188                 v += *name++;
189         /* v = hash_long(v, magic_bit); */
190         v %= nhash->nh_num;
191         return nhash->nh_head + v;
192 }
193
194 static int au_nhash_test_name(struct au_vdir_destr *str, const char *name,
195                               int nlen)
196 {
197         return str->len == nlen && !memcmp(str->name, name, nlen);
198 }
199
200 /* returns found or not */
201 int au_nhash_test_known_wh(struct au_nhash *whlist, char *name, int nlen)
202 {
203         struct hlist_head *head;
204         struct au_vdir_wh *tpos;
205         struct hlist_node *pos;
206         struct au_vdir_destr *str;
207
208         head = au_name_hash(whlist, name, nlen);
209         hlist_for_each_entry(tpos, pos, head, wh_hash) {
210                 str = &tpos->wh_str;
211                 AuDbg("%.*s\n", str->len, str->name);
212                 if (au_nhash_test_name(str, name, nlen))
213                         return 1;
214         }
215         return 0;
216 }
217
218 /* returns found(true) or not */
219 static int test_known(struct au_nhash *delist, char *name, int nlen)
220 {
221         struct hlist_head *head;
222         struct au_vdir_dehstr *tpos;
223         struct hlist_node *pos;
224         struct au_vdir_destr *str;
225
226         head = au_name_hash(delist, name, nlen);
227         hlist_for_each_entry(tpos, pos, head, hash) {
228                 str = tpos->str;
229                 AuDbg("%.*s\n", str->len, str->name);
230                 if (au_nhash_test_name(str, name, nlen))
231                         return 1;
232         }
233         return 0;
234 }
235
236 static void au_shwh_init_wh(struct au_vdir_wh *wh, ino_t ino,
237                             unsigned char d_type)
238 {
239 #ifdef CONFIG_AUFS_SHWH
240         wh->wh_ino = ino;
241         wh->wh_type = d_type;
242 #endif
243 }
244
245 /* ---------------------------------------------------------------------- */
246
247 int au_nhash_append_wh(struct au_nhash *whlist, char *name, int nlen, ino_t ino,
248                        unsigned int d_type, aufs_bindex_t bindex,
249                        unsigned char shwh)
250 {
251         int err;
252         struct au_vdir_destr *str;
253         struct au_vdir_wh *wh;
254
255         AuDbg("%.*s\n", nlen, name);
256         AuDebugOn(!whlist->nh_num || !whlist->nh_head);
257
258         err = -ENOMEM;
259         wh = kmalloc(sizeof(*wh) + nlen, GFP_NOFS);
260         if (unlikely(!wh))
261                 goto out;
262
263         err = 0;
264         wh->wh_bindex = bindex;
265         if (shwh)
266                 au_shwh_init_wh(wh, ino, d_type);
267         str = &wh->wh_str;
268         str->len = nlen;
269         memcpy(str->name, name, nlen);
270         hlist_add_head(&wh->wh_hash, au_name_hash(whlist, name, nlen));
271         /* smp_mb(); */
272
273 out:
274         return err;
275 }
276
277 static int append_deblk(struct au_vdir *vdir)
278 {
279         int err;
280         unsigned long ul;
281         const unsigned int deblk_sz = vdir->vd_deblk_sz;
282         union au_vdir_deblk_p p, deblk_end;
283         unsigned char **o;
284
285         err = -ENOMEM;
286         o = krealloc(vdir->vd_deblk, sizeof(*o) * (vdir->vd_nblk + 1),
287                      GFP_NOFS);
288         if (unlikely(!o))
289                 goto out;
290
291         vdir->vd_deblk = o;
292         p.deblk = kmalloc(deblk_sz, GFP_NOFS);
293         if (p.deblk) {
294                 ul = vdir->vd_nblk++;
295                 vdir->vd_deblk[ul] = p.deblk;
296                 vdir->vd_last.ul = ul;
297                 vdir->vd_last.p.deblk = p.deblk;
298                 deblk_end.deblk = p.deblk + deblk_sz;
299                 err = set_deblk_end(&p, &deblk_end);
300         }
301
302 out:
303         return err;
304 }
305
306 static int append_de(struct au_vdir *vdir, char *name, int nlen, ino_t ino,
307                      unsigned int d_type, struct au_nhash *delist)
308 {
309         int err;
310         unsigned int sz;
311         const unsigned int deblk_sz = vdir->vd_deblk_sz;
312         union au_vdir_deblk_p p, *room, deblk_end;
313         struct au_vdir_dehstr *dehstr;
314
315         p.deblk = last_deblk(vdir);
316         deblk_end.deblk = p.deblk + deblk_sz;
317         room = &vdir->vd_last.p;
318         AuDebugOn(room->deblk < p.deblk || deblk_end.deblk <= room->deblk
319                   || !is_deblk_end(room, &deblk_end));
320
321         sz = calc_size(nlen);
322         if (unlikely(sz > deblk_end.deblk - room->deblk)) {
323                 err = append_deblk(vdir);
324                 if (unlikely(err))
325                         goto out;
326
327                 p.deblk = last_deblk(vdir);
328                 deblk_end.deblk = p.deblk + deblk_sz;
329                 /* smp_mb(); */
330                 AuDebugOn(room->deblk != p.deblk);
331         }
332
333         err = -ENOMEM;
334         dehstr = au_cache_alloc_vdir_dehstr();
335         if (unlikely(!dehstr))
336                 goto out;
337
338         dehstr->str = &room->de->de_str;
339         hlist_add_head(&dehstr->hash, au_name_hash(delist, name, nlen));
340         room->de->de_ino = ino;
341         room->de->de_type = d_type;
342         room->de->de_str.len = nlen;
343         memcpy(room->de->de_str.name, name, nlen);
344
345         err = 0;
346         room->deblk += sz;
347         if (unlikely(set_deblk_end(room, &deblk_end)))
348                 err = append_deblk(vdir);
349         /* smp_mb(); */
350
351 out:
352         return err;
353 }
354
355 /* ---------------------------------------------------------------------- */
356
357 void au_vdir_free(struct au_vdir *vdir)
358 {
359         unsigned char **deblk;
360
361         deblk = vdir->vd_deblk;
362         while (vdir->vd_nblk--)
363                 kfree(*deblk++);
364         kfree(vdir->vd_deblk);
365         au_cache_free_vdir(vdir);
366 }
367
368 static struct au_vdir *alloc_vdir(struct file *file)
369 {
370         struct au_vdir *vdir;
371         struct super_block *sb;
372         int err;
373
374         sb = file->f_dentry->d_sb;
375         SiMustAnyLock(sb);
376
377         err = -ENOMEM;
378         vdir = au_cache_alloc_vdir();
379         if (unlikely(!vdir))
380                 goto out;
381
382         vdir->vd_deblk = kzalloc(sizeof(*vdir->vd_deblk), GFP_NOFS);
383         if (unlikely(!vdir->vd_deblk))
384                 goto out_free;
385
386         vdir->vd_deblk_sz = au_sbi(sb)->si_rdblk;
387         if (!vdir->vd_deblk_sz) {
388                 /* estimate the apropriate size for deblk */
389                 vdir->vd_deblk_sz = au_dir_size(file, /*dentry*/NULL);
390                 /* pr_info("vd_deblk_sz %u\n", vdir->vd_deblk_sz); */
391         }
392         vdir->vd_nblk = 0;
393         vdir->vd_version = 0;
394         vdir->vd_jiffy = 0;
395         err = append_deblk(vdir);
396         if (!err)
397                 return vdir; /* success */
398
399         kfree(vdir->vd_deblk);
400
401 out_free:
402         au_cache_free_vdir(vdir);
403 out:
404         vdir = ERR_PTR(err);
405         return vdir;
406 }
407
408 static int reinit_vdir(struct au_vdir *vdir)
409 {
410         int err;
411         union au_vdir_deblk_p p, deblk_end;
412
413         while (vdir->vd_nblk > 1) {
414                 kfree(vdir->vd_deblk[vdir->vd_nblk - 1]);
415                 /* vdir->vd_deblk[vdir->vd_nblk - 1] = NULL; */
416                 vdir->vd_nblk--;
417         }
418         p.deblk = vdir->vd_deblk[0];
419         deblk_end.deblk = p.deblk + vdir->vd_deblk_sz;
420         err = set_deblk_end(&p, &deblk_end);
421         /* keep vd_dblk_sz */
422         vdir->vd_last.ul = 0;
423         vdir->vd_last.p.deblk = vdir->vd_deblk[0];
424         vdir->vd_version = 0;
425         vdir->vd_jiffy = 0;
426         /* smp_mb(); */
427         return err;
428 }
429
430 /* ---------------------------------------------------------------------- */
431
432 #define AuFillVdir_CALLED       1
433 #define AuFillVdir_WHABLE       (1 << 1)
434 #define AuFillVdir_SHWH         (1 << 2)
435 #define au_ftest_fillvdir(flags, name)  ((flags) & AuFillVdir_##name)
436 #define au_fset_fillvdir(flags, name) \
437         do { (flags) |= AuFillVdir_##name; } while (0)
438 #define au_fclr_fillvdir(flags, name) \
439         do { (flags) &= ~AuFillVdir_##name; } while (0)
440
441 #ifndef CONFIG_AUFS_SHWH
442 #undef AuFillVdir_SHWH
443 #define AuFillVdir_SHWH         0
444 #endif
445
446 struct fillvdir_arg {
447         struct file             *file;
448         struct au_vdir          *vdir;
449         struct au_nhash         delist;
450         struct au_nhash         whlist;
451         aufs_bindex_t           bindex;
452         unsigned int            flags;
453         int                     err;
454 };
455
456 static int fillvdir(void *__arg, const char *__name, int nlen,
457                     loff_t offset __maybe_unused, u64 h_ino,
458                     unsigned int d_type)
459 {
460         struct fillvdir_arg *arg = __arg;
461         char *name = (void *)__name;
462         struct super_block *sb;
463         ino_t ino;
464         const unsigned char shwh = !!au_ftest_fillvdir(arg->flags, SHWH);
465
466         arg->err = 0;
467         sb = arg->file->f_dentry->d_sb;
468         au_fset_fillvdir(arg->flags, CALLED);
469         /* smp_mb(); */
470         if (nlen <= AUFS_WH_PFX_LEN
471             || memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) {
472                 if (test_known(&arg->delist, name, nlen)
473                     || au_nhash_test_known_wh(&arg->whlist, name, nlen))
474                         goto out; /* already exists or whiteouted */
475
476                 sb = arg->file->f_dentry->d_sb;
477                 arg->err = au_ino(sb, arg->bindex, h_ino, d_type, &ino);
478                 if (!arg->err) {
479                         if (unlikely(nlen > AUFS_MAX_NAMELEN))
480                                 d_type = DT_UNKNOWN;
481                         arg->err = append_de(arg->vdir, name, nlen, ino,
482                                              d_type, &arg->delist);
483                 }
484         } else if (au_ftest_fillvdir(arg->flags, WHABLE)) {
485                 name += AUFS_WH_PFX_LEN;
486                 nlen -= AUFS_WH_PFX_LEN;
487                 if (au_nhash_test_known_wh(&arg->whlist, name, nlen))
488                         goto out; /* already whiteouted */
489
490                 if (shwh)
491                         arg->err = au_wh_ino(sb, arg->bindex, h_ino, d_type,
492                                              &ino);
493                 if (!arg->err) {
494                         if (nlen <= AUFS_MAX_NAMELEN + AUFS_WH_PFX_LEN)
495                                 d_type = DT_UNKNOWN;
496                         arg->err = au_nhash_append_wh
497                                 (&arg->whlist, name, nlen, ino, d_type,
498                                  arg->bindex, shwh);
499                 }
500         }
501
502 out:
503         if (!arg->err)
504                 arg->vdir->vd_jiffy = jiffies;
505         /* smp_mb(); */
506         AuTraceErr(arg->err);
507         return arg->err;
508 }
509
510 static int au_handle_shwh(struct super_block *sb, struct au_vdir *vdir,
511                           struct au_nhash *whlist, struct au_nhash *delist)
512 {
513 #ifdef CONFIG_AUFS_SHWH
514         int err;
515         unsigned int nh, u;
516         struct hlist_head *head;
517         struct au_vdir_wh *tpos;
518         struct hlist_node *pos, *n;
519         char *p, *o;
520         struct au_vdir_destr *destr;
521
522         AuDebugOn(!au_opt_test(au_mntflags(sb), SHWH));
523
524         err = -ENOMEM;
525         o = p = __getname_gfp(GFP_NOFS);
526         if (unlikely(!p))
527                 goto out;
528
529         err = 0;
530         nh = whlist->nh_num;
531         memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN);
532         p += AUFS_WH_PFX_LEN;
533         for (u = 0; u < nh; u++) {
534                 head = whlist->nh_head + u;
535                 hlist_for_each_entry_safe(tpos, pos, n, head, wh_hash) {
536                         destr = &tpos->wh_str;
537                         memcpy(p, destr->name, destr->len);
538                         err = append_de(vdir, o, destr->len + AUFS_WH_PFX_LEN,
539                                         tpos->wh_ino, tpos->wh_type, delist);
540                         if (unlikely(err))
541                                 break;
542                 }
543         }
544
545         __putname(o);
546
547 out:
548         AuTraceErr(err);
549         return err;
550 #else
551         return 0;
552 #endif
553 }
554
555 static int au_do_read_vdir(struct fillvdir_arg *arg)
556 {
557         int err;
558         unsigned int rdhash;
559         loff_t offset;
560         aufs_bindex_t bend, bindex, bstart;
561         unsigned char shwh;
562         struct file *hf, *file;
563         struct super_block *sb;
564
565         file = arg->file;
566         sb = file->f_dentry->d_sb;
567         SiMustAnyLock(sb);
568
569         rdhash = au_sbi(sb)->si_rdhash;
570         if (!rdhash)
571                 rdhash = au_rdhash_est(au_dir_size(file, /*dentry*/NULL));
572         err = au_nhash_alloc(&arg->delist, rdhash, GFP_NOFS);
573         if (unlikely(err))
574                 goto out;
575         err = au_nhash_alloc(&arg->whlist, rdhash, GFP_NOFS);
576         if (unlikely(err))
577                 goto out_delist;
578
579         err = 0;
580         arg->flags = 0;
581         shwh = 0;
582         if (au_opt_test(au_mntflags(sb), SHWH)) {
583                 shwh = 1;
584                 au_fset_fillvdir(arg->flags, SHWH);
585         }
586         bstart = au_fbstart(file);
587         bend = au_fbend_dir(file);
588         for (bindex = bstart; !err && bindex <= bend; bindex++) {
589                 hf = au_hf_dir(file, bindex);
590                 if (!hf)
591                         continue;
592
593                 offset = vfsub_llseek(hf, 0, SEEK_SET);
594                 err = offset;
595                 if (unlikely(offset))
596                         break;
597
598                 arg->bindex = bindex;
599                 au_fclr_fillvdir(arg->flags, WHABLE);
600                 if (shwh
601                     || (bindex != bend
602                         && au_br_whable(au_sbr_perm(sb, bindex))))
603                         au_fset_fillvdir(arg->flags, WHABLE);
604                 do {
605                         arg->err = 0;
606                         au_fclr_fillvdir(arg->flags, CALLED);
607                         /* smp_mb(); */
608                         err = vfsub_readdir(hf, fillvdir, arg);
609                         if (err >= 0)
610                                 err = arg->err;
611                 } while (!err && au_ftest_fillvdir(arg->flags, CALLED));
612         }
613
614         if (!err && shwh)
615                 err = au_handle_shwh(sb, arg->vdir, &arg->whlist, &arg->delist);
616
617         au_nhash_wh_free(&arg->whlist);
618
619 out_delist:
620         au_nhash_de_free(&arg->delist);
621 out:
622         return err;
623 }
624
625 static int read_vdir(struct file *file, int may_read)
626 {
627         int err;
628         unsigned long expire;
629         unsigned char do_read;
630         struct fillvdir_arg arg;
631         struct inode *inode;
632         struct au_vdir *vdir, *allocated;
633
634         err = 0;
635         inode = file->f_dentry->d_inode;
636         IMustLock(inode);
637         SiMustAnyLock(inode->i_sb);
638
639         allocated = NULL;
640         do_read = 0;
641         expire = au_sbi(inode->i_sb)->si_rdcache;
642         vdir = au_ivdir(inode);
643         if (!vdir) {
644                 do_read = 1;
645                 vdir = alloc_vdir(file);
646                 err = PTR_ERR(vdir);
647                 if (IS_ERR(vdir))
648                         goto out;
649                 err = 0;
650                 allocated = vdir;
651         } else if (may_read
652                    && (inode->i_version != vdir->vd_version
653                        || time_after(jiffies, vdir->vd_jiffy + expire))) {
654                 do_read = 1;
655                 err = reinit_vdir(vdir);
656                 if (unlikely(err))
657                         goto out;
658         }
659
660         if (!do_read)
661                 return 0; /* success */
662
663         arg.file = file;
664         arg.vdir = vdir;
665         err = au_do_read_vdir(&arg);
666         if (!err) {
667                 /* file->f_pos = 0; */
668                 vdir->vd_version = inode->i_version;
669                 vdir->vd_last.ul = 0;
670                 vdir->vd_last.p.deblk = vdir->vd_deblk[0];
671                 if (allocated)
672                         au_set_ivdir(inode, allocated);
673         } else if (allocated)
674                 au_vdir_free(allocated);
675
676 out:
677         return err;
678 }
679
680 static int copy_vdir(struct au_vdir *tgt, struct au_vdir *src)
681 {
682         int err, rerr;
683         unsigned long ul, n;
684         const unsigned int deblk_sz = src->vd_deblk_sz;
685
686         AuDebugOn(tgt->vd_nblk != 1);
687
688         err = -ENOMEM;
689         if (tgt->vd_nblk < src->vd_nblk) {
690                 unsigned char **p;
691
692                 p = krealloc(tgt->vd_deblk, sizeof(*p) * src->vd_nblk,
693                              GFP_NOFS);
694                 if (unlikely(!p))
695                         goto out;
696                 tgt->vd_deblk = p;
697         }
698
699         if (tgt->vd_deblk_sz != deblk_sz) {
700                 unsigned char *p;
701
702                 tgt->vd_deblk_sz = deblk_sz;
703                 p = krealloc(tgt->vd_deblk[0], deblk_sz, GFP_NOFS);
704                 if (unlikely(!p))
705                         goto out;
706                 tgt->vd_deblk[0] = p;
707         }
708         memcpy(tgt->vd_deblk[0], src->vd_deblk[0], deblk_sz);
709         tgt->vd_version = src->vd_version;
710         tgt->vd_jiffy = src->vd_jiffy;
711
712         n = src->vd_nblk;
713         for (ul = 1; ul < n; ul++) {
714                 tgt->vd_deblk[ul] = kmemdup(src->vd_deblk[ul], deblk_sz,
715                                             GFP_NOFS);
716                 if (unlikely(!tgt->vd_deblk[ul]))
717                         goto out;
718                 tgt->vd_nblk++;
719         }
720         tgt->vd_nblk = n;
721         tgt->vd_last.ul = tgt->vd_last.ul;
722         tgt->vd_last.p.deblk = tgt->vd_deblk[tgt->vd_last.ul];
723         tgt->vd_last.p.deblk += src->vd_last.p.deblk
724                 - src->vd_deblk[src->vd_last.ul];
725         /* smp_mb(); */
726         return 0; /* success */
727
728 out:
729         rerr = reinit_vdir(tgt);
730         BUG_ON(rerr);
731         return err;
732 }
733
734 int au_vdir_init(struct file *file)
735 {
736         int err;
737         struct inode *inode;
738         struct au_vdir *vdir_cache, *allocated;
739
740         err = read_vdir(file, !file->f_pos);
741         if (unlikely(err))
742                 goto out;
743
744         allocated = NULL;
745         vdir_cache = au_fvdir_cache(file);
746         if (!vdir_cache) {
747                 vdir_cache = alloc_vdir(file);
748                 err = PTR_ERR(vdir_cache);
749                 if (IS_ERR(vdir_cache))
750                         goto out;
751                 allocated = vdir_cache;
752         } else if (!file->f_pos && vdir_cache->vd_version != file->f_version) {
753                 err = reinit_vdir(vdir_cache);
754                 if (unlikely(err))
755                         goto out;
756         } else
757                 return 0; /* success */
758
759         inode = file->f_dentry->d_inode;
760         err = copy_vdir(vdir_cache, au_ivdir(inode));
761         if (!err) {
762                 file->f_version = inode->i_version;
763                 if (allocated)
764                         au_set_fvdir_cache(file, allocated);
765         } else if (allocated)
766                 au_vdir_free(allocated);
767
768 out:
769         return err;
770 }
771
772 static loff_t calc_offset(struct au_vdir *vdir)
773 {
774         loff_t offset;
775         union au_vdir_deblk_p p;
776
777         p.deblk = vdir->vd_deblk[vdir->vd_last.ul];
778         offset = vdir->vd_last.p.deblk - p.deblk;
779         offset += vdir->vd_deblk_sz * vdir->vd_last.ul;
780         return offset;
781 }
782
783 /* returns true or false */
784 static int seek_vdir(struct file *file)
785 {
786         int valid;
787         unsigned int deblk_sz;
788         unsigned long ul, n;
789         loff_t offset;
790         union au_vdir_deblk_p p, deblk_end;
791         struct au_vdir *vdir_cache;
792
793         valid = 1;
794         vdir_cache = au_fvdir_cache(file);
795         offset = calc_offset(vdir_cache);
796         AuDbg("offset %lld\n", offset);
797         if (file->f_pos == offset)
798                 goto out;
799
800         vdir_cache->vd_last.ul = 0;
801         vdir_cache->vd_last.p.deblk = vdir_cache->vd_deblk[0];
802         if (!file->f_pos)
803                 goto out;
804
805         valid = 0;
806         deblk_sz = vdir_cache->vd_deblk_sz;
807         ul = div64_u64(file->f_pos, deblk_sz);
808         AuDbg("ul %lu\n", ul);
809         if (ul >= vdir_cache->vd_nblk)
810                 goto out;
811
812         n = vdir_cache->vd_nblk;
813         for (; ul < n; ul++) {
814                 p.deblk = vdir_cache->vd_deblk[ul];
815                 deblk_end.deblk = p.deblk + deblk_sz;
816                 offset = ul;
817                 offset *= deblk_sz;
818                 while (!is_deblk_end(&p, &deblk_end) && offset < file->f_pos) {
819                         unsigned int l;
820
821                         l = calc_size(p.de->de_str.len);
822                         offset += l;
823                         p.deblk += l;
824                 }
825                 if (!is_deblk_end(&p, &deblk_end)) {
826                         valid = 1;
827                         vdir_cache->vd_last.ul = ul;
828                         vdir_cache->vd_last.p = p;
829                         break;
830                 }
831         }
832
833 out:
834         /* smp_mb(); */
835         AuTraceErr(!valid);
836         return valid;
837 }
838
839 int au_vdir_fill_de(struct file *file, void *dirent, filldir_t filldir)
840 {
841         int err;
842         unsigned int l, deblk_sz;
843         union au_vdir_deblk_p deblk_end;
844         struct au_vdir *vdir_cache;
845         struct au_vdir_de *de;
846
847         vdir_cache = au_fvdir_cache(file);
848         if (!seek_vdir(file))
849                 return 0;
850
851         deblk_sz = vdir_cache->vd_deblk_sz;
852         while (1) {
853                 deblk_end.deblk = vdir_cache->vd_deblk[vdir_cache->vd_last.ul];
854                 deblk_end.deblk += deblk_sz;
855                 while (!is_deblk_end(&vdir_cache->vd_last.p, &deblk_end)) {
856                         de = vdir_cache->vd_last.p.de;
857                         AuDbg("%.*s, off%lld, i%lu, dt%d\n",
858                               de->de_str.len, de->de_str.name, file->f_pos,
859                               (unsigned long)de->de_ino, de->de_type);
860                         err = filldir(dirent, de->de_str.name, de->de_str.len,
861                                       file->f_pos, de->de_ino, de->de_type);
862                         if (unlikely(err)) {
863                                 AuTraceErr(err);
864                                 /* todo: ignore the error caused by udba? */
865                                 /* return err; */
866                                 return 0;
867                         }
868
869                         l = calc_size(de->de_str.len);
870                         vdir_cache->vd_last.p.deblk += l;
871                         file->f_pos += l;
872                 }
873                 if (vdir_cache->vd_last.ul < vdir_cache->vd_nblk - 1) {
874                         vdir_cache->vd_last.ul++;
875                         vdir_cache->vd_last.p.deblk
876                                 = vdir_cache->vd_deblk[vdir_cache->vd_last.ul];
877                         file->f_pos = deblk_sz * vdir_cache->vd_last.ul;
878                         continue;
879                 }
880                 break;
881         }
882
883         /* smp_mb(); */
884         return 0;
885 }