2 * Copyright (C) 2005-2017 Junjiro R. Okajima
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.
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.
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/>.
19 * virtual or vertical directory
24 static unsigned int calc_size(int nlen
)
26 return ALIGN(sizeof(struct au_vdir_de
) + nlen
, sizeof(ino_t
));
29 static int set_deblk_end(union au_vdir_deblk_p
*p
,
30 union au_vdir_deblk_p
*deblk_end
)
32 if (calc_size(0) <= deblk_end
->deblk
- p
->deblk
) {
33 p
->de
->de_str
.len
= 0;
37 return -1; /* error */
40 /* returns true or false */
41 static int is_deblk_end(union au_vdir_deblk_p
*p
,
42 union au_vdir_deblk_p
*deblk_end
)
44 if (calc_size(0) <= deblk_end
->deblk
- p
->deblk
)
45 return !p
->de
->de_str
.len
;
49 static unsigned char *last_deblk(struct au_vdir
*vdir
)
51 return vdir
->vd_deblk
[vdir
->vd_nblk
- 1];
54 /* ---------------------------------------------------------------------- */
56 /* estimate the appropriate size for name hash table */
57 unsigned int au_rdhash_est(loff_t sz
)
65 if (sz
< AUFS_RDHASH_DEF
)
67 /* pr_info("n %u\n", n); */
72 * the allocated memory has to be freed by
73 * au_nhash_wh_free() or au_nhash_de_free().
75 int au_nhash_alloc(struct au_nhash
*nhash
, unsigned int num_hash
, gfp_t gfp
)
77 struct hlist_head
*head
;
81 sz
= sizeof(*nhash
->nh_head
) * num_hash
;
82 head
= kmalloc(sz
, gfp
);
84 nhash
->nh_num
= num_hash
;
85 nhash
->nh_head
= head
;
86 for (u
= 0; u
< num_hash
; u
++)
87 INIT_HLIST_HEAD(head
++);
88 return 0; /* success */
94 static void nhash_count(struct hlist_head
*head
)
98 struct hlist_node
*pos
;
101 hlist_for_each(pos
, head
)
107 static void au_nhash_wh_do_free(struct hlist_head
*head
)
109 struct au_vdir_wh
*pos
;
110 struct hlist_node
*node
;
112 hlist_for_each_entry_safe(pos
, node
, head
, wh_hash
)
116 static void au_nhash_de_do_free(struct hlist_head
*head
)
118 struct au_vdir_dehstr
*pos
;
119 struct hlist_node
*node
;
121 hlist_for_each_entry_safe(pos
, node
, head
, hash
)
122 au_cache_free_vdir_dehstr(pos
);
125 static void au_nhash_do_free(struct au_nhash
*nhash
,
126 void (*free
)(struct hlist_head
*head
))
129 struct hlist_head
*head
;
135 head
= nhash
->nh_head
;
140 kfree(nhash
->nh_head
);
143 void au_nhash_wh_free(struct au_nhash
*whlist
)
145 au_nhash_do_free(whlist
, au_nhash_wh_do_free
);
148 static void au_nhash_de_free(struct au_nhash
*delist
)
150 au_nhash_do_free(delist
, au_nhash_de_do_free
);
153 /* ---------------------------------------------------------------------- */
155 int au_nhash_test_longer_wh(struct au_nhash
*whlist
, aufs_bindex_t btgt
,
160 struct hlist_head
*head
;
161 struct au_vdir_wh
*pos
;
165 head
= whlist
->nh_head
;
166 for (u
= 0; u
< n
; u
++, head
++)
167 hlist_for_each_entry(pos
, head
, wh_hash
)
168 if (pos
->wh_bindex
== btgt
&& ++num
> limit
)
173 static struct hlist_head
*au_name_hash(struct au_nhash
*nhash
,
178 /* const unsigned int magic_bit = 12; */
180 AuDebugOn(!nhash
->nh_num
|| !nhash
->nh_head
);
187 /* v = hash_long(v, magic_bit); */
189 return nhash
->nh_head
+ v
;
192 static int au_nhash_test_name(struct au_vdir_destr
*str
, const char *name
,
195 return str
->len
== nlen
&& !memcmp(str
->name
, name
, nlen
);
198 /* returns found or not */
199 int au_nhash_test_known_wh(struct au_nhash
*whlist
, char *name
, int nlen
)
201 struct hlist_head
*head
;
202 struct au_vdir_wh
*pos
;
203 struct au_vdir_destr
*str
;
205 head
= au_name_hash(whlist
, name
, nlen
);
206 hlist_for_each_entry(pos
, head
, wh_hash
) {
208 AuDbg("%.*s\n", str
->len
, str
->name
);
209 if (au_nhash_test_name(str
, name
, nlen
))
215 /* returns found(true) or not */
216 static int test_known(struct au_nhash
*delist
, char *name
, int nlen
)
218 struct hlist_head
*head
;
219 struct au_vdir_dehstr
*pos
;
220 struct au_vdir_destr
*str
;
222 head
= au_name_hash(delist
, name
, nlen
);
223 hlist_for_each_entry(pos
, head
, hash
) {
225 AuDbg("%.*s\n", str
->len
, str
->name
);
226 if (au_nhash_test_name(str
, name
, nlen
))
232 static void au_shwh_init_wh(struct au_vdir_wh
*wh
, ino_t ino
,
233 unsigned char d_type
)
235 #ifdef CONFIG_AUFS_SHWH
237 wh
->wh_type
= d_type
;
241 /* ---------------------------------------------------------------------- */
243 int au_nhash_append_wh(struct au_nhash
*whlist
, char *name
, int nlen
, ino_t ino
,
244 unsigned int d_type
, aufs_bindex_t bindex
,
248 struct au_vdir_destr
*str
;
249 struct au_vdir_wh
*wh
;
251 AuDbg("%.*s\n", nlen
, name
);
252 AuDebugOn(!whlist
->nh_num
|| !whlist
->nh_head
);
255 wh
= kmalloc(sizeof(*wh
) + nlen
, GFP_NOFS
);
260 wh
->wh_bindex
= bindex
;
262 au_shwh_init_wh(wh
, ino
, d_type
);
265 memcpy(str
->name
, name
, nlen
);
266 hlist_add_head(&wh
->wh_hash
, au_name_hash(whlist
, name
, nlen
));
273 static int append_deblk(struct au_vdir
*vdir
)
277 const unsigned int deblk_sz
= vdir
->vd_deblk_sz
;
278 union au_vdir_deblk_p p
, deblk_end
;
282 o
= au_krealloc(vdir
->vd_deblk
, sizeof(*o
) * (vdir
->vd_nblk
+ 1),
283 GFP_NOFS
, /*may_shrink*/0);
288 p
.deblk
= kmalloc(deblk_sz
, GFP_NOFS
);
290 ul
= vdir
->vd_nblk
++;
291 vdir
->vd_deblk
[ul
] = p
.deblk
;
292 vdir
->vd_last
.ul
= ul
;
293 vdir
->vd_last
.p
.deblk
= p
.deblk
;
294 deblk_end
.deblk
= p
.deblk
+ deblk_sz
;
295 err
= set_deblk_end(&p
, &deblk_end
);
302 static int append_de(struct au_vdir
*vdir
, char *name
, int nlen
, ino_t ino
,
303 unsigned int d_type
, struct au_nhash
*delist
)
307 const unsigned int deblk_sz
= vdir
->vd_deblk_sz
;
308 union au_vdir_deblk_p p
, *room
, deblk_end
;
309 struct au_vdir_dehstr
*dehstr
;
311 p
.deblk
= last_deblk(vdir
);
312 deblk_end
.deblk
= p
.deblk
+ deblk_sz
;
313 room
= &vdir
->vd_last
.p
;
314 AuDebugOn(room
->deblk
< p
.deblk
|| deblk_end
.deblk
<= room
->deblk
315 || !is_deblk_end(room
, &deblk_end
));
317 sz
= calc_size(nlen
);
318 if (unlikely(sz
> deblk_end
.deblk
- room
->deblk
)) {
319 err
= append_deblk(vdir
);
323 p
.deblk
= last_deblk(vdir
);
324 deblk_end
.deblk
= p
.deblk
+ deblk_sz
;
326 AuDebugOn(room
->deblk
!= p
.deblk
);
330 dehstr
= au_cache_alloc_vdir_dehstr();
331 if (unlikely(!dehstr
))
334 dehstr
->str
= &room
->de
->de_str
;
335 hlist_add_head(&dehstr
->hash
, au_name_hash(delist
, name
, nlen
));
336 room
->de
->de_ino
= ino
;
337 room
->de
->de_type
= d_type
;
338 room
->de
->de_str
.len
= nlen
;
339 memcpy(room
->de
->de_str
.name
, name
, nlen
);
343 if (unlikely(set_deblk_end(room
, &deblk_end
)))
344 err
= append_deblk(vdir
);
351 /* ---------------------------------------------------------------------- */
353 void au_vdir_free(struct au_vdir
*vdir
)
355 unsigned char **deblk
;
357 deblk
= vdir
->vd_deblk
;
358 while (vdir
->vd_nblk
--)
360 kfree(vdir
->vd_deblk
);
361 au_cache_free_vdir(vdir
);
364 static struct au_vdir
*alloc_vdir(struct file
*file
)
366 struct au_vdir
*vdir
;
367 struct super_block
*sb
;
370 sb
= file
->f_path
.dentry
->d_sb
;
374 vdir
= au_cache_alloc_vdir();
378 vdir
->vd_deblk
= kzalloc(sizeof(*vdir
->vd_deblk
), GFP_NOFS
);
379 if (unlikely(!vdir
->vd_deblk
))
382 vdir
->vd_deblk_sz
= au_sbi(sb
)->si_rdblk
;
383 if (!vdir
->vd_deblk_sz
) {
384 /* estimate the appropriate size for deblk */
385 vdir
->vd_deblk_sz
= au_dir_size(file
, /*dentry*/NULL
);
386 /* pr_info("vd_deblk_sz %u\n", vdir->vd_deblk_sz); */
389 vdir
->vd_version
= 0;
391 err
= append_deblk(vdir
);
393 return vdir
; /* success */
395 kfree(vdir
->vd_deblk
);
398 au_cache_free_vdir(vdir
);
404 static int reinit_vdir(struct au_vdir
*vdir
)
407 union au_vdir_deblk_p p
, deblk_end
;
409 while (vdir
->vd_nblk
> 1) {
410 kfree(vdir
->vd_deblk
[vdir
->vd_nblk
- 1]);
411 /* vdir->vd_deblk[vdir->vd_nblk - 1] = NULL; */
414 p
.deblk
= vdir
->vd_deblk
[0];
415 deblk_end
.deblk
= p
.deblk
+ vdir
->vd_deblk_sz
;
416 err
= set_deblk_end(&p
, &deblk_end
);
417 /* keep vd_dblk_sz */
418 vdir
->vd_last
.ul
= 0;
419 vdir
->vd_last
.p
.deblk
= vdir
->vd_deblk
[0];
420 vdir
->vd_version
= 0;
426 /* ---------------------------------------------------------------------- */
428 #define AuFillVdir_CALLED 1
429 #define AuFillVdir_WHABLE (1 << 1)
430 #define AuFillVdir_SHWH (1 << 2)
431 #define au_ftest_fillvdir(flags, name) ((flags) & AuFillVdir_##name)
432 #define au_fset_fillvdir(flags, name) \
433 do { (flags) |= AuFillVdir_##name; } while (0)
434 #define au_fclr_fillvdir(flags, name) \
435 do { (flags) &= ~AuFillVdir_##name; } while (0)
437 #ifndef CONFIG_AUFS_SHWH
438 #undef AuFillVdir_SHWH
439 #define AuFillVdir_SHWH 0
442 struct fillvdir_arg
{
443 struct dir_context ctx
;
445 struct au_vdir
*vdir
;
446 struct au_nhash delist
;
447 struct au_nhash whlist
;
448 aufs_bindex_t bindex
;
453 static int fillvdir(struct dir_context
*ctx
, const char *__name
, int nlen
,
454 loff_t offset __maybe_unused
, u64 h_ino
,
457 struct fillvdir_arg
*arg
= container_of(ctx
, struct fillvdir_arg
, ctx
);
458 char *name
= (void *)__name
;
459 struct super_block
*sb
;
461 const unsigned char shwh
= !!au_ftest_fillvdir(arg
->flags
, SHWH
);
464 sb
= arg
->file
->f_path
.dentry
->d_sb
;
465 au_fset_fillvdir(arg
->flags
, CALLED
);
467 if (nlen
<= AUFS_WH_PFX_LEN
468 || memcmp(name
, AUFS_WH_PFX
, AUFS_WH_PFX_LEN
)) {
469 if (test_known(&arg
->delist
, name
, nlen
)
470 || au_nhash_test_known_wh(&arg
->whlist
, name
, nlen
))
471 goto out
; /* already exists or whiteouted */
473 arg
->err
= au_ino(sb
, arg
->bindex
, h_ino
, d_type
, &ino
);
475 if (unlikely(nlen
> AUFS_MAX_NAMELEN
))
477 arg
->err
= append_de(arg
->vdir
, name
, nlen
, ino
,
478 d_type
, &arg
->delist
);
480 } else if (au_ftest_fillvdir(arg
->flags
, WHABLE
)) {
481 name
+= AUFS_WH_PFX_LEN
;
482 nlen
-= AUFS_WH_PFX_LEN
;
483 if (au_nhash_test_known_wh(&arg
->whlist
, name
, nlen
))
484 goto out
; /* already whiteouted */
487 arg
->err
= au_wh_ino(sb
, arg
->bindex
, h_ino
, d_type
,
490 if (nlen
<= AUFS_MAX_NAMELEN
+ AUFS_WH_PFX_LEN
)
492 arg
->err
= au_nhash_append_wh
493 (&arg
->whlist
, name
, nlen
, ino
, d_type
,
500 arg
->vdir
->vd_jiffy
= jiffies
;
502 AuTraceErr(arg
->err
);
506 static int au_handle_shwh(struct super_block
*sb
, struct au_vdir
*vdir
,
507 struct au_nhash
*whlist
, struct au_nhash
*delist
)
509 #ifdef CONFIG_AUFS_SHWH
512 struct hlist_head
*head
;
513 struct au_vdir_wh
*pos
;
514 struct hlist_node
*n
;
516 struct au_vdir_destr
*destr
;
518 AuDebugOn(!au_opt_test(au_mntflags(sb
), SHWH
));
521 o
= p
= (void *)__get_free_page(GFP_NOFS
);
527 memcpy(p
, AUFS_WH_PFX
, AUFS_WH_PFX_LEN
);
528 p
+= AUFS_WH_PFX_LEN
;
529 for (u
= 0; u
< nh
; u
++) {
530 head
= whlist
->nh_head
+ u
;
531 hlist_for_each_entry_safe(pos
, n
, head
, wh_hash
) {
532 destr
= &pos
->wh_str
;
533 memcpy(p
, destr
->name
, destr
->len
);
534 err
= append_de(vdir
, o
, destr
->len
+ AUFS_WH_PFX_LEN
,
535 pos
->wh_ino
, pos
->wh_type
, delist
);
541 free_page((unsigned long)o
);
551 static int au_do_read_vdir(struct fillvdir_arg
*arg
)
556 aufs_bindex_t bbot
, bindex
, btop
;
558 struct file
*hf
, *file
;
559 struct super_block
*sb
;
562 sb
= file
->f_path
.dentry
->d_sb
;
565 rdhash
= au_sbi(sb
)->si_rdhash
;
567 rdhash
= au_rdhash_est(au_dir_size(file
, /*dentry*/NULL
));
568 err
= au_nhash_alloc(&arg
->delist
, rdhash
, GFP_NOFS
);
571 err
= au_nhash_alloc(&arg
->whlist
, rdhash
, GFP_NOFS
);
578 if (au_opt_test(au_mntflags(sb
), SHWH
)) {
580 au_fset_fillvdir(arg
->flags
, SHWH
);
582 btop
= au_fbtop(file
);
583 bbot
= au_fbbot_dir(file
);
584 for (bindex
= btop
; !err
&& bindex
<= bbot
; bindex
++) {
585 hf
= au_hf_dir(file
, bindex
);
589 offset
= vfsub_llseek(hf
, 0, SEEK_SET
);
591 if (unlikely(offset
))
594 arg
->bindex
= bindex
;
595 au_fclr_fillvdir(arg
->flags
, WHABLE
);
598 && au_br_whable(au_sbr_perm(sb
, bindex
))))
599 au_fset_fillvdir(arg
->flags
, WHABLE
);
602 au_fclr_fillvdir(arg
->flags
, CALLED
);
604 err
= vfsub_iterate_dir(hf
, &arg
->ctx
);
607 } while (!err
&& au_ftest_fillvdir(arg
->flags
, CALLED
));
610 * dir_relax() may be good for concurrency, but aufs should not
611 * use it since it will cause a lockdep problem.
616 err
= au_handle_shwh(sb
, arg
->vdir
, &arg
->whlist
, &arg
->delist
);
618 au_nhash_wh_free(&arg
->whlist
);
621 au_nhash_de_free(&arg
->delist
);
626 static int read_vdir(struct file
*file
, int may_read
)
629 unsigned long expire
;
630 unsigned char do_read
;
631 struct fillvdir_arg arg
= {
637 struct au_vdir
*vdir
, *allocated
;
640 inode
= file_inode(file
);
642 IiMustWriteLock(inode
);
643 SiMustAnyLock(inode
->i_sb
);
647 expire
= au_sbi(inode
->i_sb
)->si_rdcache
;
648 vdir
= au_ivdir(inode
);
651 vdir
= alloc_vdir(file
);
658 && (inode
->i_version
!= vdir
->vd_version
659 || time_after(jiffies
, vdir
->vd_jiffy
+ expire
))) {
661 err
= reinit_vdir(vdir
);
667 return 0; /* success */
671 err
= au_do_read_vdir(&arg
);
673 /* file->f_pos = 0; */ /* todo: ctx->pos? */
674 vdir
->vd_version
= inode
->i_version
;
675 vdir
->vd_last
.ul
= 0;
676 vdir
->vd_last
.p
.deblk
= vdir
->vd_deblk
[0];
678 au_set_ivdir(inode
, allocated
);
679 } else if (allocated
)
680 au_vdir_free(allocated
);
686 static int copy_vdir(struct au_vdir
*tgt
, struct au_vdir
*src
)
690 const unsigned int deblk_sz
= src
->vd_deblk_sz
;
692 AuDebugOn(tgt
->vd_nblk
!= 1);
695 if (tgt
->vd_nblk
< src
->vd_nblk
) {
698 p
= au_krealloc(tgt
->vd_deblk
, sizeof(*p
) * src
->vd_nblk
,
699 GFP_NOFS
, /*may_shrink*/0);
705 if (tgt
->vd_deblk_sz
!= deblk_sz
) {
708 tgt
->vd_deblk_sz
= deblk_sz
;
709 p
= au_krealloc(tgt
->vd_deblk
[0], deblk_sz
, GFP_NOFS
,
713 tgt
->vd_deblk
[0] = p
;
715 memcpy(tgt
->vd_deblk
[0], src
->vd_deblk
[0], deblk_sz
);
716 tgt
->vd_version
= src
->vd_version
;
717 tgt
->vd_jiffy
= src
->vd_jiffy
;
720 for (ul
= 1; ul
< n
; ul
++) {
721 tgt
->vd_deblk
[ul
] = kmemdup(src
->vd_deblk
[ul
], deblk_sz
,
723 if (unlikely(!tgt
->vd_deblk
[ul
]))
728 tgt
->vd_last
.ul
= tgt
->vd_last
.ul
;
729 tgt
->vd_last
.p
.deblk
= tgt
->vd_deblk
[tgt
->vd_last
.ul
];
730 tgt
->vd_last
.p
.deblk
+= src
->vd_last
.p
.deblk
731 - src
->vd_deblk
[src
->vd_last
.ul
];
733 return 0; /* success */
736 rerr
= reinit_vdir(tgt
);
741 int au_vdir_init(struct file
*file
)
745 struct au_vdir
*vdir_cache
, *allocated
;
747 /* test file->f_pos here instead of ctx->pos */
748 err
= read_vdir(file
, !file
->f_pos
);
753 vdir_cache
= au_fvdir_cache(file
);
755 vdir_cache
= alloc_vdir(file
);
756 err
= PTR_ERR(vdir_cache
);
757 if (IS_ERR(vdir_cache
))
759 allocated
= vdir_cache
;
760 } else if (!file
->f_pos
&& vdir_cache
->vd_version
!= file
->f_version
) {
761 /* test file->f_pos here instead of ctx->pos */
762 err
= reinit_vdir(vdir_cache
);
766 return 0; /* success */
768 inode
= file_inode(file
);
769 err
= copy_vdir(vdir_cache
, au_ivdir(inode
));
771 file
->f_version
= inode
->i_version
;
773 au_set_fvdir_cache(file
, allocated
);
774 } else if (allocated
)
775 au_vdir_free(allocated
);
781 static loff_t
calc_offset(struct au_vdir
*vdir
)
784 union au_vdir_deblk_p p
;
786 p
.deblk
= vdir
->vd_deblk
[vdir
->vd_last
.ul
];
787 offset
= vdir
->vd_last
.p
.deblk
- p
.deblk
;
788 offset
+= vdir
->vd_deblk_sz
* vdir
->vd_last
.ul
;
792 /* returns true or false */
793 static int seek_vdir(struct file
*file
, struct dir_context
*ctx
)
796 unsigned int deblk_sz
;
799 union au_vdir_deblk_p p
, deblk_end
;
800 struct au_vdir
*vdir_cache
;
803 vdir_cache
= au_fvdir_cache(file
);
804 offset
= calc_offset(vdir_cache
);
805 AuDbg("offset %lld\n", offset
);
806 if (ctx
->pos
== offset
)
809 vdir_cache
->vd_last
.ul
= 0;
810 vdir_cache
->vd_last
.p
.deblk
= vdir_cache
->vd_deblk
[0];
815 deblk_sz
= vdir_cache
->vd_deblk_sz
;
816 ul
= div64_u64(ctx
->pos
, deblk_sz
);
817 AuDbg("ul %lu\n", ul
);
818 if (ul
>= vdir_cache
->vd_nblk
)
821 n
= vdir_cache
->vd_nblk
;
822 for (; ul
< n
; ul
++) {
823 p
.deblk
= vdir_cache
->vd_deblk
[ul
];
824 deblk_end
.deblk
= p
.deblk
+ deblk_sz
;
827 while (!is_deblk_end(&p
, &deblk_end
) && offset
< ctx
->pos
) {
830 l
= calc_size(p
.de
->de_str
.len
);
834 if (!is_deblk_end(&p
, &deblk_end
)) {
836 vdir_cache
->vd_last
.ul
= ul
;
837 vdir_cache
->vd_last
.p
= p
;
848 int au_vdir_fill_de(struct file
*file
, struct dir_context
*ctx
)
850 unsigned int l
, deblk_sz
;
851 union au_vdir_deblk_p deblk_end
;
852 struct au_vdir
*vdir_cache
;
853 struct au_vdir_de
*de
;
855 vdir_cache
= au_fvdir_cache(file
);
856 if (!seek_vdir(file
, ctx
))
859 deblk_sz
= vdir_cache
->vd_deblk_sz
;
861 deblk_end
.deblk
= vdir_cache
->vd_deblk
[vdir_cache
->vd_last
.ul
];
862 deblk_end
.deblk
+= deblk_sz
;
863 while (!is_deblk_end(&vdir_cache
->vd_last
.p
, &deblk_end
)) {
864 de
= vdir_cache
->vd_last
.p
.de
;
865 AuDbg("%.*s, off%lld, i%lu, dt%d\n",
866 de
->de_str
.len
, de
->de_str
.name
, ctx
->pos
,
867 (unsigned long)de
->de_ino
, de
->de_type
);
868 if (unlikely(!dir_emit(ctx
, de
->de_str
.name
,
869 de
->de_str
.len
, de
->de_ino
,
871 /* todo: ignore the error caused by udba? */
876 l
= calc_size(de
->de_str
.len
);
877 vdir_cache
->vd_last
.p
.deblk
+= l
;
880 if (vdir_cache
->vd_last
.ul
< vdir_cache
->vd_nblk
- 1) {
881 vdir_cache
->vd_last
.ul
++;
882 vdir_cache
->vd_last
.p
.deblk
883 = vdir_cache
->vd_deblk
[vdir_cache
->vd_last
.ul
];
884 ctx
->pos
= deblk_sz
* vdir_cache
->vd_last
.ul
;