diff options
author | André Fabian Silva Delgado <emulatorman@parabola.nu> | 2015-09-08 01:01:14 -0300 |
---|---|---|
committer | André Fabian Silva Delgado <emulatorman@parabola.nu> | 2015-09-08 01:01:14 -0300 |
commit | e5fd91f1ef340da553f7a79da9540c3db711c937 (patch) | |
tree | b11842027dc6641da63f4bcc524f8678263304a3 /fs/aufs/vdir.c | |
parent | 2a9b0348e685a63d97486f6749622b61e9e3292f (diff) |
Linux-libre 4.2-gnu
Diffstat (limited to 'fs/aufs/vdir.c')
-rw-r--r-- | fs/aufs/vdir.c | 888 |
1 files changed, 0 insertions, 888 deletions
diff --git a/fs/aufs/vdir.c b/fs/aufs/vdir.c deleted file mode 100644 index 0929d393a..000000000 --- a/fs/aufs/vdir.c +++ /dev/null @@ -1,888 +0,0 @@ -/* - * Copyright (C) 2005-2015 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -/* - * virtual or vertical directory - */ - -#include "aufs.h" - -static unsigned int calc_size(int nlen) -{ - return ALIGN(sizeof(struct au_vdir_de) + nlen, sizeof(ino_t)); -} - -static int set_deblk_end(union au_vdir_deblk_p *p, - union au_vdir_deblk_p *deblk_end) -{ - if (calc_size(0) <= deblk_end->deblk - p->deblk) { - p->de->de_str.len = 0; - /* smp_mb(); */ - return 0; - } - return -1; /* error */ -} - -/* returns true or false */ -static int is_deblk_end(union au_vdir_deblk_p *p, - union au_vdir_deblk_p *deblk_end) -{ - if (calc_size(0) <= deblk_end->deblk - p->deblk) - return !p->de->de_str.len; - return 1; -} - -static unsigned char *last_deblk(struct au_vdir *vdir) -{ - return vdir->vd_deblk[vdir->vd_nblk - 1]; -} - -/* ---------------------------------------------------------------------- */ - -/* estimate the apropriate size for name hash table */ -unsigned int au_rdhash_est(loff_t sz) -{ - unsigned int n; - - n = UINT_MAX; - sz >>= 10; - if (sz < n) - n = sz; - if (sz < AUFS_RDHASH_DEF) - n = AUFS_RDHASH_DEF; - /* pr_info("n %u\n", n); */ - return n; -} - -/* - * the allocated memory has to be freed by - * au_nhash_wh_free() or au_nhash_de_free(). - */ -int au_nhash_alloc(struct au_nhash *nhash, unsigned int num_hash, gfp_t gfp) -{ - struct hlist_head *head; - unsigned int u; - size_t sz; - - sz = sizeof(*nhash->nh_head) * num_hash; - head = kmalloc(sz, gfp); - if (head) { - nhash->nh_num = num_hash; - nhash->nh_head = head; - for (u = 0; u < num_hash; u++) - INIT_HLIST_HEAD(head++); - return 0; /* success */ - } - - return -ENOMEM; -} - -static void nhash_count(struct hlist_head *head) -{ -#if 0 - unsigned long n; - struct hlist_node *pos; - - n = 0; - hlist_for_each(pos, head) - n++; - pr_info("%lu\n", n); -#endif -} - -static void au_nhash_wh_do_free(struct hlist_head *head) -{ - struct au_vdir_wh *pos; - struct hlist_node *node; - - hlist_for_each_entry_safe(pos, node, head, wh_hash) - kfree(pos); -} - -static void au_nhash_de_do_free(struct hlist_head *head) -{ - struct au_vdir_dehstr *pos; - struct hlist_node *node; - - hlist_for_each_entry_safe(pos, node, head, hash) - au_cache_free_vdir_dehstr(pos); -} - -static void au_nhash_do_free(struct au_nhash *nhash, - void (*free)(struct hlist_head *head)) -{ - unsigned int n; - struct hlist_head *head; - - n = nhash->nh_num; - if (!n) - return; - - head = nhash->nh_head; - while (n-- > 0) { - nhash_count(head); - free(head++); - } - kfree(nhash->nh_head); -} - -void au_nhash_wh_free(struct au_nhash *whlist) -{ - au_nhash_do_free(whlist, au_nhash_wh_do_free); -} - -static void au_nhash_de_free(struct au_nhash *delist) -{ - au_nhash_do_free(delist, au_nhash_de_do_free); -} - -/* ---------------------------------------------------------------------- */ - -int au_nhash_test_longer_wh(struct au_nhash *whlist, aufs_bindex_t btgt, - int limit) -{ - int num; - unsigned int u, n; - struct hlist_head *head; - struct au_vdir_wh *pos; - - num = 0; - n = whlist->nh_num; - head = whlist->nh_head; - for (u = 0; u < n; u++, head++) - hlist_for_each_entry(pos, head, wh_hash) - if (pos->wh_bindex == btgt && ++num > limit) - return 1; - return 0; -} - -static struct hlist_head *au_name_hash(struct au_nhash *nhash, - unsigned char *name, - unsigned int len) -{ - unsigned int v; - /* const unsigned int magic_bit = 12; */ - - AuDebugOn(!nhash->nh_num || !nhash->nh_head); - - v = 0; - while (len--) - v += *name++; - /* v = hash_long(v, magic_bit); */ - v %= nhash->nh_num; - return nhash->nh_head + v; -} - -static int au_nhash_test_name(struct au_vdir_destr *str, const char *name, - int nlen) -{ - return str->len == nlen && !memcmp(str->name, name, nlen); -} - -/* returns found or not */ -int au_nhash_test_known_wh(struct au_nhash *whlist, char *name, int nlen) -{ - struct hlist_head *head; - struct au_vdir_wh *pos; - struct au_vdir_destr *str; - - head = au_name_hash(whlist, name, nlen); - hlist_for_each_entry(pos, head, wh_hash) { - str = &pos->wh_str; - AuDbg("%.*s\n", str->len, str->name); - if (au_nhash_test_name(str, name, nlen)) - return 1; - } - return 0; -} - -/* returns found(true) or not */ -static int test_known(struct au_nhash *delist, char *name, int nlen) -{ - struct hlist_head *head; - struct au_vdir_dehstr *pos; - struct au_vdir_destr *str; - - head = au_name_hash(delist, name, nlen); - hlist_for_each_entry(pos, head, hash) { - str = pos->str; - AuDbg("%.*s\n", str->len, str->name); - if (au_nhash_test_name(str, name, nlen)) - return 1; - } - return 0; -} - -static void au_shwh_init_wh(struct au_vdir_wh *wh, ino_t ino, - unsigned char d_type) -{ -#ifdef CONFIG_AUFS_SHWH - wh->wh_ino = ino; - wh->wh_type = d_type; -#endif -} - -/* ---------------------------------------------------------------------- */ - -int au_nhash_append_wh(struct au_nhash *whlist, char *name, int nlen, ino_t ino, - unsigned int d_type, aufs_bindex_t bindex, - unsigned char shwh) -{ - int err; - struct au_vdir_destr *str; - struct au_vdir_wh *wh; - - AuDbg("%.*s\n", nlen, name); - AuDebugOn(!whlist->nh_num || !whlist->nh_head); - - err = -ENOMEM; - wh = kmalloc(sizeof(*wh) + nlen, GFP_NOFS); - if (unlikely(!wh)) - goto out; - - err = 0; - wh->wh_bindex = bindex; - if (shwh) - au_shwh_init_wh(wh, ino, d_type); - str = &wh->wh_str; - str->len = nlen; - memcpy(str->name, name, nlen); - hlist_add_head(&wh->wh_hash, au_name_hash(whlist, name, nlen)); - /* smp_mb(); */ - -out: - return err; -} - -static int append_deblk(struct au_vdir *vdir) -{ - int err; - unsigned long ul; - const unsigned int deblk_sz = vdir->vd_deblk_sz; - union au_vdir_deblk_p p, deblk_end; - unsigned char **o; - - err = -ENOMEM; - o = krealloc(vdir->vd_deblk, sizeof(*o) * (vdir->vd_nblk + 1), - GFP_NOFS); - if (unlikely(!o)) - goto out; - - vdir->vd_deblk = o; - p.deblk = kmalloc(deblk_sz, GFP_NOFS); - if (p.deblk) { - ul = vdir->vd_nblk++; - vdir->vd_deblk[ul] = p.deblk; - vdir->vd_last.ul = ul; - vdir->vd_last.p.deblk = p.deblk; - deblk_end.deblk = p.deblk + deblk_sz; - err = set_deblk_end(&p, &deblk_end); - } - -out: - return err; -} - -static int append_de(struct au_vdir *vdir, char *name, int nlen, ino_t ino, - unsigned int d_type, struct au_nhash *delist) -{ - int err; - unsigned int sz; - const unsigned int deblk_sz = vdir->vd_deblk_sz; - union au_vdir_deblk_p p, *room, deblk_end; - struct au_vdir_dehstr *dehstr; - - p.deblk = last_deblk(vdir); - deblk_end.deblk = p.deblk + deblk_sz; - room = &vdir->vd_last.p; - AuDebugOn(room->deblk < p.deblk || deblk_end.deblk <= room->deblk - || !is_deblk_end(room, &deblk_end)); - - sz = calc_size(nlen); - if (unlikely(sz > deblk_end.deblk - room->deblk)) { - err = append_deblk(vdir); - if (unlikely(err)) - goto out; - - p.deblk = last_deblk(vdir); - deblk_end.deblk = p.deblk + deblk_sz; - /* smp_mb(); */ - AuDebugOn(room->deblk != p.deblk); - } - - err = -ENOMEM; - dehstr = au_cache_alloc_vdir_dehstr(); - if (unlikely(!dehstr)) - goto out; - - dehstr->str = &room->de->de_str; - hlist_add_head(&dehstr->hash, au_name_hash(delist, name, nlen)); - room->de->de_ino = ino; - room->de->de_type = d_type; - room->de->de_str.len = nlen; - memcpy(room->de->de_str.name, name, nlen); - - err = 0; - room->deblk += sz; - if (unlikely(set_deblk_end(room, &deblk_end))) - err = append_deblk(vdir); - /* smp_mb(); */ - -out: - return err; -} - -/* ---------------------------------------------------------------------- */ - -void au_vdir_free(struct au_vdir *vdir) -{ - unsigned char **deblk; - - deblk = vdir->vd_deblk; - while (vdir->vd_nblk--) - kfree(*deblk++); - kfree(vdir->vd_deblk); - au_cache_free_vdir(vdir); -} - -static struct au_vdir *alloc_vdir(struct file *file) -{ - struct au_vdir *vdir; - struct super_block *sb; - int err; - - sb = file->f_path.dentry->d_sb; - SiMustAnyLock(sb); - - err = -ENOMEM; - vdir = au_cache_alloc_vdir(); - if (unlikely(!vdir)) - goto out; - - vdir->vd_deblk = kzalloc(sizeof(*vdir->vd_deblk), GFP_NOFS); - if (unlikely(!vdir->vd_deblk)) - goto out_free; - - vdir->vd_deblk_sz = au_sbi(sb)->si_rdblk; - if (!vdir->vd_deblk_sz) { - /* estimate the apropriate size for deblk */ - vdir->vd_deblk_sz = au_dir_size(file, /*dentry*/NULL); - /* pr_info("vd_deblk_sz %u\n", vdir->vd_deblk_sz); */ - } - vdir->vd_nblk = 0; - vdir->vd_version = 0; - vdir->vd_jiffy = 0; - err = append_deblk(vdir); - if (!err) - return vdir; /* success */ - - kfree(vdir->vd_deblk); - -out_free: - au_cache_free_vdir(vdir); -out: - vdir = ERR_PTR(err); - return vdir; -} - -static int reinit_vdir(struct au_vdir *vdir) -{ - int err; - union au_vdir_deblk_p p, deblk_end; - - while (vdir->vd_nblk > 1) { - kfree(vdir->vd_deblk[vdir->vd_nblk - 1]); - /* vdir->vd_deblk[vdir->vd_nblk - 1] = NULL; */ - vdir->vd_nblk--; - } - p.deblk = vdir->vd_deblk[0]; - deblk_end.deblk = p.deblk + vdir->vd_deblk_sz; - err = set_deblk_end(&p, &deblk_end); - /* keep vd_dblk_sz */ - vdir->vd_last.ul = 0; - vdir->vd_last.p.deblk = vdir->vd_deblk[0]; - vdir->vd_version = 0; - vdir->vd_jiffy = 0; - /* smp_mb(); */ - return err; -} - -/* ---------------------------------------------------------------------- */ - -#define AuFillVdir_CALLED 1 -#define AuFillVdir_WHABLE (1 << 1) -#define AuFillVdir_SHWH (1 << 2) -#define au_ftest_fillvdir(flags, name) ((flags) & AuFillVdir_##name) -#define au_fset_fillvdir(flags, name) \ - do { (flags) |= AuFillVdir_##name; } while (0) -#define au_fclr_fillvdir(flags, name) \ - do { (flags) &= ~AuFillVdir_##name; } while (0) - -#ifndef CONFIG_AUFS_SHWH -#undef AuFillVdir_SHWH -#define AuFillVdir_SHWH 0 -#endif - -struct fillvdir_arg { - struct dir_context ctx; - struct file *file; - struct au_vdir *vdir; - struct au_nhash delist; - struct au_nhash whlist; - aufs_bindex_t bindex; - unsigned int flags; - int err; -}; - -static int fillvdir(struct dir_context *ctx, const char *__name, int nlen, - loff_t offset __maybe_unused, u64 h_ino, - unsigned int d_type) -{ - struct fillvdir_arg *arg = container_of(ctx, struct fillvdir_arg, ctx); - char *name = (void *)__name; - struct super_block *sb; - ino_t ino; - const unsigned char shwh = !!au_ftest_fillvdir(arg->flags, SHWH); - - arg->err = 0; - sb = arg->file->f_path.dentry->d_sb; - au_fset_fillvdir(arg->flags, CALLED); - /* smp_mb(); */ - if (nlen <= AUFS_WH_PFX_LEN - || memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { - if (test_known(&arg->delist, name, nlen) - || au_nhash_test_known_wh(&arg->whlist, name, nlen)) - goto out; /* already exists or whiteouted */ - - arg->err = au_ino(sb, arg->bindex, h_ino, d_type, &ino); - if (!arg->err) { - if (unlikely(nlen > AUFS_MAX_NAMELEN)) - d_type = DT_UNKNOWN; - arg->err = append_de(arg->vdir, name, nlen, ino, - d_type, &arg->delist); - } - } else if (au_ftest_fillvdir(arg->flags, WHABLE)) { - name += AUFS_WH_PFX_LEN; - nlen -= AUFS_WH_PFX_LEN; - if (au_nhash_test_known_wh(&arg->whlist, name, nlen)) - goto out; /* already whiteouted */ - - if (shwh) - arg->err = au_wh_ino(sb, arg->bindex, h_ino, d_type, - &ino); - if (!arg->err) { - if (nlen <= AUFS_MAX_NAMELEN + AUFS_WH_PFX_LEN) - d_type = DT_UNKNOWN; - arg->err = au_nhash_append_wh - (&arg->whlist, name, nlen, ino, d_type, - arg->bindex, shwh); - } - } - -out: - if (!arg->err) - arg->vdir->vd_jiffy = jiffies; - /* smp_mb(); */ - AuTraceErr(arg->err); - return arg->err; -} - -static int au_handle_shwh(struct super_block *sb, struct au_vdir *vdir, - struct au_nhash *whlist, struct au_nhash *delist) -{ -#ifdef CONFIG_AUFS_SHWH - int err; - unsigned int nh, u; - struct hlist_head *head; - struct au_vdir_wh *pos; - struct hlist_node *n; - char *p, *o; - struct au_vdir_destr *destr; - - AuDebugOn(!au_opt_test(au_mntflags(sb), SHWH)); - - err = -ENOMEM; - o = p = (void *)__get_free_page(GFP_NOFS); - if (unlikely(!p)) - goto out; - - err = 0; - nh = whlist->nh_num; - memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); - p += AUFS_WH_PFX_LEN; - for (u = 0; u < nh; u++) { - head = whlist->nh_head + u; - hlist_for_each_entry_safe(pos, n, head, wh_hash) { - destr = &pos->wh_str; - memcpy(p, destr->name, destr->len); - err = append_de(vdir, o, destr->len + AUFS_WH_PFX_LEN, - pos->wh_ino, pos->wh_type, delist); - if (unlikely(err)) - break; - } - } - - free_page((unsigned long)o); - -out: - AuTraceErr(err); - return err; -#else - return 0; -#endif -} - -static int au_do_read_vdir(struct fillvdir_arg *arg) -{ - int err; - unsigned int rdhash; - loff_t offset; - aufs_bindex_t bend, bindex, bstart; - unsigned char shwh; - struct file *hf, *file; - struct super_block *sb; - - file = arg->file; - sb = file->f_path.dentry->d_sb; - SiMustAnyLock(sb); - - rdhash = au_sbi(sb)->si_rdhash; - if (!rdhash) - rdhash = au_rdhash_est(au_dir_size(file, /*dentry*/NULL)); - err = au_nhash_alloc(&arg->delist, rdhash, GFP_NOFS); - if (unlikely(err)) - goto out; - err = au_nhash_alloc(&arg->whlist, rdhash, GFP_NOFS); - if (unlikely(err)) - goto out_delist; - - err = 0; - arg->flags = 0; - shwh = 0; - if (au_opt_test(au_mntflags(sb), SHWH)) { - shwh = 1; - au_fset_fillvdir(arg->flags, SHWH); - } - bstart = au_fbstart(file); - bend = au_fbend_dir(file); - for (bindex = bstart; !err && bindex <= bend; bindex++) { - hf = au_hf_dir(file, bindex); - if (!hf) - continue; - - offset = vfsub_llseek(hf, 0, SEEK_SET); - err = offset; - if (unlikely(offset)) - break; - - arg->bindex = bindex; - au_fclr_fillvdir(arg->flags, WHABLE); - if (shwh - || (bindex != bend - && au_br_whable(au_sbr_perm(sb, bindex)))) - au_fset_fillvdir(arg->flags, WHABLE); - do { - arg->err = 0; - au_fclr_fillvdir(arg->flags, CALLED); - /* smp_mb(); */ - err = vfsub_iterate_dir(hf, &arg->ctx); - if (err >= 0) - err = arg->err; - } while (!err && au_ftest_fillvdir(arg->flags, CALLED)); - - /* - * dir_relax() may be good for concurrency, but aufs should not - * use it since it will cause a lockdep problem. - */ - } - - if (!err && shwh) - err = au_handle_shwh(sb, arg->vdir, &arg->whlist, &arg->delist); - - au_nhash_wh_free(&arg->whlist); - -out_delist: - au_nhash_de_free(&arg->delist); -out: - return err; -} - -static int read_vdir(struct file *file, int may_read) -{ - int err; - unsigned long expire; - unsigned char do_read; - struct fillvdir_arg arg = { - .ctx = { - .actor = fillvdir - } - }; - struct inode *inode; - struct au_vdir *vdir, *allocated; - - err = 0; - inode = file_inode(file); - IMustLock(inode); - SiMustAnyLock(inode->i_sb); - - allocated = NULL; - do_read = 0; - expire = au_sbi(inode->i_sb)->si_rdcache; - vdir = au_ivdir(inode); - if (!vdir) { - do_read = 1; - vdir = alloc_vdir(file); - err = PTR_ERR(vdir); - if (IS_ERR(vdir)) - goto out; - err = 0; - allocated = vdir; - } else if (may_read - && (inode->i_version != vdir->vd_version - || time_after(jiffies, vdir->vd_jiffy + expire))) { - do_read = 1; - err = reinit_vdir(vdir); - if (unlikely(err)) - goto out; - } - - if (!do_read) - return 0; /* success */ - - arg.file = file; - arg.vdir = vdir; - err = au_do_read_vdir(&arg); - if (!err) { - /* file->f_pos = 0; */ /* todo: ctx->pos? */ - vdir->vd_version = inode->i_version; - vdir->vd_last.ul = 0; - vdir->vd_last.p.deblk = vdir->vd_deblk[0]; - if (allocated) - au_set_ivdir(inode, allocated); - } else if (allocated) - au_vdir_free(allocated); - -out: - return err; -} - -static int copy_vdir(struct au_vdir *tgt, struct au_vdir *src) -{ - int err, rerr; - unsigned long ul, n; - const unsigned int deblk_sz = src->vd_deblk_sz; - - AuDebugOn(tgt->vd_nblk != 1); - - err = -ENOMEM; - if (tgt->vd_nblk < src->vd_nblk) { - unsigned char **p; - - p = krealloc(tgt->vd_deblk, sizeof(*p) * src->vd_nblk, - GFP_NOFS); - if (unlikely(!p)) - goto out; - tgt->vd_deblk = p; - } - - if (tgt->vd_deblk_sz != deblk_sz) { - unsigned char *p; - - tgt->vd_deblk_sz = deblk_sz; - p = krealloc(tgt->vd_deblk[0], deblk_sz, GFP_NOFS); - if (unlikely(!p)) - goto out; - tgt->vd_deblk[0] = p; - } - memcpy(tgt->vd_deblk[0], src->vd_deblk[0], deblk_sz); - tgt->vd_version = src->vd_version; - tgt->vd_jiffy = src->vd_jiffy; - - n = src->vd_nblk; - for (ul = 1; ul < n; ul++) { - tgt->vd_deblk[ul] = kmemdup(src->vd_deblk[ul], deblk_sz, - GFP_NOFS); - if (unlikely(!tgt->vd_deblk[ul])) - goto out; - tgt->vd_nblk++; - } - tgt->vd_nblk = n; - tgt->vd_last.ul = tgt->vd_last.ul; - tgt->vd_last.p.deblk = tgt->vd_deblk[tgt->vd_last.ul]; - tgt->vd_last.p.deblk += src->vd_last.p.deblk - - src->vd_deblk[src->vd_last.ul]; - /* smp_mb(); */ - return 0; /* success */ - -out: - rerr = reinit_vdir(tgt); - BUG_ON(rerr); - return err; -} - -int au_vdir_init(struct file *file) -{ - int err; - struct inode *inode; - struct au_vdir *vdir_cache, *allocated; - - /* test file->f_pos here instead of ctx->pos */ - err = read_vdir(file, !file->f_pos); - if (unlikely(err)) - goto out; - - allocated = NULL; - vdir_cache = au_fvdir_cache(file); - if (!vdir_cache) { - vdir_cache = alloc_vdir(file); - err = PTR_ERR(vdir_cache); - if (IS_ERR(vdir_cache)) - goto out; - allocated = vdir_cache; - } else if (!file->f_pos && vdir_cache->vd_version != file->f_version) { - /* test file->f_pos here instead of ctx->pos */ - err = reinit_vdir(vdir_cache); - if (unlikely(err)) - goto out; - } else - return 0; /* success */ - - inode = file_inode(file); - err = copy_vdir(vdir_cache, au_ivdir(inode)); - if (!err) { - file->f_version = inode->i_version; - if (allocated) - au_set_fvdir_cache(file, allocated); - } else if (allocated) - au_vdir_free(allocated); - -out: - return err; -} - -static loff_t calc_offset(struct au_vdir *vdir) -{ - loff_t offset; - union au_vdir_deblk_p p; - - p.deblk = vdir->vd_deblk[vdir->vd_last.ul]; - offset = vdir->vd_last.p.deblk - p.deblk; - offset += vdir->vd_deblk_sz * vdir->vd_last.ul; - return offset; -} - -/* returns true or false */ -static int seek_vdir(struct file *file, struct dir_context *ctx) -{ - int valid; - unsigned int deblk_sz; - unsigned long ul, n; - loff_t offset; - union au_vdir_deblk_p p, deblk_end; - struct au_vdir *vdir_cache; - - valid = 1; - vdir_cache = au_fvdir_cache(file); - offset = calc_offset(vdir_cache); - AuDbg("offset %lld\n", offset); - if (ctx->pos == offset) - goto out; - - vdir_cache->vd_last.ul = 0; - vdir_cache->vd_last.p.deblk = vdir_cache->vd_deblk[0]; - if (!ctx->pos) - goto out; - - valid = 0; - deblk_sz = vdir_cache->vd_deblk_sz; - ul = div64_u64(ctx->pos, deblk_sz); - AuDbg("ul %lu\n", ul); - if (ul >= vdir_cache->vd_nblk) - goto out; - - n = vdir_cache->vd_nblk; - for (; ul < n; ul++) { - p.deblk = vdir_cache->vd_deblk[ul]; - deblk_end.deblk = p.deblk + deblk_sz; - offset = ul; - offset *= deblk_sz; - while (!is_deblk_end(&p, &deblk_end) && offset < ctx->pos) { - unsigned int l; - - l = calc_size(p.de->de_str.len); - offset += l; - p.deblk += l; - } - if (!is_deblk_end(&p, &deblk_end)) { - valid = 1; - vdir_cache->vd_last.ul = ul; - vdir_cache->vd_last.p = p; - break; - } - } - -out: - /* smp_mb(); */ - AuTraceErr(!valid); - return valid; -} - -int au_vdir_fill_de(struct file *file, struct dir_context *ctx) -{ - unsigned int l, deblk_sz; - union au_vdir_deblk_p deblk_end; - struct au_vdir *vdir_cache; - struct au_vdir_de *de; - - vdir_cache = au_fvdir_cache(file); - if (!seek_vdir(file, ctx)) - return 0; - - deblk_sz = vdir_cache->vd_deblk_sz; - while (1) { - deblk_end.deblk = vdir_cache->vd_deblk[vdir_cache->vd_last.ul]; - deblk_end.deblk += deblk_sz; - while (!is_deblk_end(&vdir_cache->vd_last.p, &deblk_end)) { - de = vdir_cache->vd_last.p.de; - AuDbg("%.*s, off%lld, i%lu, dt%d\n", - de->de_str.len, de->de_str.name, ctx->pos, - (unsigned long)de->de_ino, de->de_type); - if (unlikely(!dir_emit(ctx, de->de_str.name, - de->de_str.len, de->de_ino, - de->de_type))) { - /* todo: ignore the error caused by udba? */ - /* return err; */ - return 0; - } - - l = calc_size(de->de_str.len); - vdir_cache->vd_last.p.deblk += l; - ctx->pos += l; - } - if (vdir_cache->vd_last.ul < vdir_cache->vd_nblk - 1) { - vdir_cache->vd_last.ul++; - vdir_cache->vd_last.p.deblk - = vdir_cache->vd_deblk[vdir_cache->vd_last.ul]; - ctx->pos = deblk_sz * vdir_cache->vd_last.ul; - continue; - } - break; - } - - /* smp_mb(); */ - return 0; -} |