- struct au_nhash supports the variable size of hash table.
- struct au_vdir supports the variable size of deblk.
- remove AuSize_DEBLK and AuSize_NHASH macros.
- replace au_nhash_{new,del,init,move,fin}() by
au_nhash_{alloc,wh_free}().
- rename struct au_whtmp_rmdir_args to struct au_whtmp_rmdir which
contains au_nhash.
- new functions au_whtmp_rmdir_{alloc,free}().
- support for variable hash table.
au_dpri_whlist(), au_test_empty_lower(), aufs_rmdir(),
au_ren_del_whtmp(), do_rename(), may_rename_srcdir(), aufs_rename(),
del_wh_children(), au_whtmp_rmdir_alloc(), au_whtmp_rmdir_free(),
call_rmdir_whtmp(), au_whtmp_kick_rmdir().
- support for variable deblk.
au_dpri_vdir(), vdir.c entirely.
Signed-off-by: J. R. Okajima <[email protected]>
---
fs/aufs/debug.c | 24 ++--
fs/aufs/dir.c | 13 +-
fs/aufs/dir.h | 33 ++---
fs/aufs/i_op_del.c | 24 +--
fs/aufs/i_op_ren.c | 39 +++--
fs/aufs/vdir.c | 438 ++++++++++++++++++++++++++--------------------------
fs/aufs/whout.c | 53 +++++--
fs/aufs/whout.h | 7 +-
8 files changed, 325 insertions(+), 306 deletions(-)
diff --git a/fs/aufs/debug.c b/fs/aufs/debug.c
index 2feba39..3339b16 100644
--- a/fs/aufs/debug.c
+++ b/fs/aufs/debug.c
@@ -37,24 +37,26 @@ char *au_plevel = KERN_DEBUG;
void au_dpri_whlist(struct au_nhash *whlist)
{
- int i;
+ unsigned long ul, n;
struct hlist_head *head;
struct au_vdir_wh *tpos;
struct hlist_node *pos;
- for (i = 0; i < AuSize_NHASH; i++) {
- head = whlist->heads + i;
+ n = whlist->nh_num;
+ head = whlist->nh_head;
+ for (ul = 0; ul < n; ul++) {
hlist_for_each_entry(tpos, pos, head, wh_hash)
dpri("b%d, %.*s, %d\n",
tpos->wh_bindex,
tpos->wh_str.len, tpos->wh_str.name,
tpos->wh_str.len);
+ head++;
}
}
void au_dpri_vdir(struct au_vdir *vdir)
{
- int i;
+ unsigned long ul;
union au_vdir_deblk_p p;
unsigned char *o;
@@ -63,13 +65,13 @@ void au_dpri_vdir(struct au_vdir *vdir)
return;
}
- dpri("nblk %d, deblk %p, last{%d, %p}, ver %lu\n",
- vdir->vd_nblk, vdir->vd_deblk,
- vdir->vd_last.i, vdir->vd_last.p.p, vdir->vd_version);
- for (i = 0; i < vdir->vd_nblk; i++) {
- p.deblk = vdir->vd_deblk[i];
- o = p.p;
- dpri("[%d]: %p\n", i, o);
+ dpri("deblk %u, nblk %lu, deblk %p, last{%lu, %p}, ver %lu\n",
+ vdir->vd_deblk_sz, vdir->vd_nblk, vdir->vd_deblk,
+ vdir->vd_last.ul, vdir->vd_last.p.deblk, vdir->vd_version);
+ for (ul = 0; ul < vdir->vd_nblk; ul++) {
+ p.deblk = vdir->vd_deblk[ul];
+ o = p.deblk;
+ dpri("[%lu]: %p\n", ul, o);
#if 0 // verbose
int j;
for (j = 0; j < 8; j++) {
diff --git a/fs/aufs/dir.c b/fs/aufs/dir.c
index 599d7f2..c722345 100644
--- a/fs/aufs/dir.c
+++ b/fs/aufs/dir.c
@@ -518,9 +518,10 @@ static int sio_test_empty(struct dentry *dentry, struct
test_empty_arg *arg)
int au_test_empty_lower(struct dentry *dentry)
{
int err;
+ unsigned int rdhash;
struct inode *inode;
+ struct au_nhash whlist;
struct test_empty_arg arg;
- struct au_nhash *whlist;
aufs_bindex_t bindex, bstart, btail;
unsigned int mnt_flags;
@@ -528,15 +529,15 @@ int au_test_empty_lower(struct dentry *dentry)
inode = dentry->d_inode;
AuDebugOn(!inode || !S_ISDIR(inode->i_mode));
- whlist = au_nhash_new(GFP_NOFS);
- err = PTR_ERR(whlist);
- if (IS_ERR(whlist))
+ rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, dentry));
+ err = au_nhash_alloc(&whlist, rdhash, GFP_NOFS);
+ if (unlikely(err))
goto out;
bstart = au_dbstart(dentry);
mnt_flags = au_mntflags(dentry->d_sb);
- arg.whlist = whlist;
arg.flags = 0;
+ arg.whlist = &whlist;
if (au_test_dlgt(mnt_flags))
au_fset_testempty(arg.flags, DLGT);
if (au_opt_test(mnt_flags, SHWH))
@@ -560,7 +561,7 @@ int au_test_empty_lower(struct dentry *dentry)
}
out_whlist:
- au_nhash_del(whlist);
+ au_nhash_wh_free(&whlist);
out:
AuTraceErr(err);
return err;
diff --git a/fs/aufs/dir.h b/fs/aufs/dir.h
index 5cf5159..161a2fd 100644
--- a/fs/aufs/dir.h
+++ b/fs/aufs/dir.h
@@ -39,24 +39,14 @@ typedef ino_t au_filldir_ino_t;
/* ---------------------------------------------------------------------- */
-/* need to be faster and smaller */
-
-/* todo: changeable? */
-#define AuSize_DEBLK 512
-#define AuSize_NHASH 32
-#if AuSize_DEBLK < NAME_MAX || PAGE_SIZE < AuSize_DEBLK
-#error invalid size AuSize_DEBLK
-#endif
-
-typedef char au_vdir_deblk_t[AuSize_DEBLK];
-
struct au_nhash {
- struct hlist_head heads[AuSize_NHASH];
+ unsigned int nh_num;
+ struct hlist_head *nh_head;
};
struct au_vdir_destr {
unsigned char len;
- char name[0];
+ unsigned char name[0];
} __packed;
struct au_vdir_dehstr {
@@ -83,16 +73,16 @@ struct au_vdir_wh {
} __packed;
union au_vdir_deblk_p {
- unsigned char *p;
- au_vdir_deblk_t *deblk;
+ unsigned char *deblk;
struct au_vdir_de *de;
};
struct au_vdir {
- au_vdir_deblk_t **vd_deblk;
- int vd_nblk;
+ unsigned char **vd_deblk;
+ unsigned long vd_nblk;
+ unsigned int vd_deblk_sz;
struct {
- int i;
+ unsigned long ul;
union au_vdir_deblk_p p;
} vd_last;
@@ -110,11 +100,8 @@ int au_test_empty(struct dentry *dentry, struct au_nhash
*whlist);
/* vdir.c */
unsigned int au_rdhash_est(loff_t sz);
-struct au_nhash *au_nhash_new(gfp_t gfp);
-void au_nhash_del(struct au_nhash *nhash);
-void au_nhash_init(struct au_nhash *nhash);
-void au_nhash_move(struct au_nhash *dst, struct au_nhash *src);
-void au_nhash_fin(struct au_nhash *nhash);
+int au_nhash_alloc(struct au_nhash *nhash, unsigned int num_hash, gfp_t gfp);
+void au_nhash_wh_free(struct au_nhash *whlist);
int au_nhash_test_longer_wh(struct au_nhash *whlist, aufs_bindex_t btgt,
int limit);
int au_nhash_test_known_wh(struct au_nhash *whlist, char *name, int namelen);
diff --git a/fs/aufs/i_op_del.c b/fs/aufs/i_op_del.c
index e2ce684..909ac92 100644
--- a/fs/aufs/i_op_del.c
+++ b/fs/aufs/i_op_del.c
@@ -456,8 +456,7 @@ int aufs_rmdir(struct inode *dir, struct dentry *dentry)
struct dentry *parent, *wh_dentry, *h_dentry;
struct au_dtime dt;
aufs_bindex_t bwh, bindex, bstart;
- struct au_whtmp_rmdir_args *args;
- struct au_nhash *whlist;
+ struct au_whtmp_rmdir *args;
struct super_block *sb;
unsigned int mnt_flags;
struct au_pin pin;
@@ -470,20 +469,15 @@ int aufs_rmdir(struct inode *dir, struct dentry *dentry)
goto out;
IMustLock(inode);
- whlist = au_nhash_new(GFP_NOFS);
- err = PTR_ERR(whlist);
- if (IS_ERR(whlist))
- goto out;
-
err = -ENOMEM;
- args = kmalloc(sizeof(*args), GFP_NOFS);
+ args = au_whtmp_rmdir_alloc(dir->i_sb, GFP_NOFS);
if (unlikely(!args))
- goto out_whlist;
+ goto out;
aufs_read_lock(dentry, AuLock_DW);
parent = dentry->d_parent; /* dir inode is locked */
di_write_lock_parent(parent);
- err = au_test_empty(dentry, whlist);
+ err = au_test_empty(dentry, &args->whlist);
if (unlikely(err))
goto out_args;
@@ -501,7 +495,7 @@ int aufs_rmdir(struct inode *dir, struct dentry *dentry)
rmdir_later = 0;
if (bindex == bstart) {
- err = renwh_and_rmdir(dentry, bstart, whlist, dir);
+ err = renwh_and_rmdir(dentry, bstart, &args->whlist, dir);
if (err > 0) {
rmdir_later = err;
err = 0;
@@ -525,8 +519,7 @@ int aufs_rmdir(struct inode *dir, struct dentry *dentry)
epilog(dir, dentry, bindex);
if (rmdir_later) {
- au_whtmp_kick_rmdir(dir, bstart, h_dentry, whlist,
- args);
+ au_whtmp_kick_rmdir(dir, bstart, h_dentry, args);
args = NULL;
}
@@ -555,9 +548,8 @@ int aufs_rmdir(struct inode *dir, struct dentry *dentry)
out_args:
di_write_unlock(parent);
aufs_read_unlock(dentry, AuLock_DW);
- kfree(args);
- out_whlist:
- au_nhash_del(whlist);
+ if (args)
+ au_whtmp_rmdir_free(args);
out:
AuTraceErr(err);
if (unlikely(err == -EBUSY && au_test_nfsd(current)))
diff --git a/fs/aufs/i_op_ren.c b/fs/aufs/i_op_ren.c
index 903da95..2b26b30 100644
--- a/fs/aufs/i_op_ren.c
+++ b/fs/aufs/i_op_ren.c
@@ -69,7 +69,7 @@ struct au_ren_args {
struct au_hin_ignore ign[2];
#endif
struct vfsub_args vargs;
- struct au_whtmp_rmdir_args *thargs;
+ struct au_whtmp_rmdir *thargs;
struct dentry *wh_dentry[2], *h_dst, *h_src;
};
@@ -255,8 +255,10 @@ int au_ren_del_whtmp(struct au_ren_args *a)
AuWarn("failed removing whtmp dir %.*s (%d), "
"ignored.\n", AuDLNPair(a->h_dst), err);
} else {
- au_whtmp_kick_rmdir(a->dir, a->btgt, a->h_dst, &a->whlist,
- a->thargs);
+ au_nhash_wh_free(&a->thargs->whlist);
+ a->thargs->whlist = a->whlist;
+ a->whlist.nh_num = 0;
+ au_whtmp_kick_rmdir(a->dir, a->btgt, a->h_dst, a->thargs);
dput(a->h_dst);
a->thargs = NULL;
}
@@ -307,7 +309,7 @@ int do_rename(struct au_ren_args *a)
/* prepare workqueue args */
if (au_ftest_ren(a->flags, ISDIR) && a->h_dentry[DST]->d_inode) {
err = -ENOMEM;
- a->thargs = kmalloc(sizeof(*a->thargs), GFP_NOFS);
+ a->thargs = au_whtmp_rmdir_alloc(a->src_dentry->d_sb, GFP_NOFS);
if (unlikely(!a->thargs))
goto out;
a->h_dst = dget(a->h_dentry[DST]);
@@ -456,7 +458,8 @@ int do_rename(struct au_ren_args *a)
out_thargs:
if (a->thargs) {
dput(a->h_dst);
- kfree(a->thargs);
+ au_whtmp_rmdir_free(a->thargs);
+ a->thargs = NULL;
}
out:
AuTraceErr(err);
@@ -492,14 +495,15 @@ static int may_rename_srcdir(struct dentry *dentry,
aufs_bindex_t btgt)
bstart = au_dbstart(dentry);
if (bstart != btgt) {
- struct au_nhash *whlist;
+ struct au_nhash whlist;
+ unsigned int rdhash;
- whlist = au_nhash_new(GFP_NOFS);
- err = PTR_ERR(whlist);
- if (IS_ERR(whlist))
+ rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, dentry));
+ err = au_nhash_alloc(&whlist, rdhash, GFP_NOFS);
+ if (unlikely(err))
goto out;
- err = au_test_empty(dentry, whlist);
- au_nhash_del(whlist);
+ err = au_test_empty(dentry, &whlist);
+ au_nhash_wh_free(&whlist);
goto out;
}
@@ -990,6 +994,7 @@ int aufs_rename(struct inode *src_dir, struct dentry
*src_dentry,
struct inode *dir, struct dentry *dentry)
{
int err;
+ unsigned int rdhash;
aufs_bindex_t bend, bindex;
unsigned char do_dt_dstdir, hinotify;
struct inode *inode[2];
@@ -1062,15 +1067,19 @@ int aufs_rename(struct inode *src_dir, struct dentry
*src_dentry,
/* are they available to be renamed */
err = 0;
- au_nhash_init(&p->a.whlist);
if (au_ftest_ren(p->a.flags, ISDIR) && inode[DST]) {
+ rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, dentry));
+ err = au_nhash_alloc(&p->a.whlist, rdhash, GFP_NOFS);
+ if (unlikely(err))
+ goto out_unlock;
+
au_set_dbstart(dentry, p->a.bstart[DST]);
err = may_rename_dstdir(dentry, p->a.btgt, &p->a.whlist);
au_set_dbstart(dentry, p->a.btgt);
}
p->a.h_dentry[DST] = au_h_dptr(dentry, au_dbstart(dentry));
if (unlikely(err))
- goto out_unlock;
+ goto out_children;
/* todo: minor optimize,
their sb may be same while their bindex differs? */
p->a.h_dentry[SRC] = au_h_dptr(src_dentry, au_dbstart(src_dentry));
@@ -1233,7 +1242,7 @@ int aufs_rename(struct inode *src_dir, struct dentry
*src_dentry,
out_hdir:
au_ren_unlock(&p->a);
out_children:
- au_nhash_fin(&p->a.whlist);
+ au_nhash_wh_free(&p->a.whlist);
out_unlock:
if (unlikely(err && au_ftest_ren(p->a.flags, ISDIR))) {
au_update_dbstart(dentry);
@@ -1254,6 +1263,8 @@ int aufs_rename(struct inode *src_dir, struct dentry
*src_dentry,
di_write_unlock2(p->a.parent[SRC], p->a.parent[DST]);
aufs_read_and_write_unlock2(dentry, src_dentry);
out_free:
+ if (p->a.thargs)
+ au_whtmp_rmdir_free(p->a.thargs);
kfree(p);
out:
iput(inode[DST]);
diff --git a/fs/aufs/vdir.c b/fs/aufs/vdir.c
index ea9ef37..e3564fd 100644
--- a/fs/aufs/vdir.c
+++ b/fs/aufs/vdir.c
@@ -24,27 +24,16 @@
#include "aufs.h"
-static int calc_size(int namelen)
+static unsigned int calc_size(int namelen)
{
- int sz;
-
- sz = sizeof(struct au_vdir_de) + namelen;
- if (sizeof(ino_t) == sizeof(long)) {
- const int mask = sizeof(ino_t) - 1;
- if (sz & mask) {
- sz += sizeof(ino_t);
- sz &= ~mask;
- }
- }
-
- AuDebugOn(sz % sizeof(ino_t));
- return sz;
+ BUILD_BUG_ON(sizeof(ino_t) != sizeof(long));
+ return ALIGN(sizeof(struct au_vdir_de) + namelen, 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->p - p->p) {
+ if (calc_size(0) <= deblk_end->deblk - p->deblk) {
p->de->de_str.len = 0;
/* smp_mb(); */
return 0;
@@ -56,16 +45,18 @@ static int set_deblk_end(union au_vdir_deblk_p *p,
static int is_deblk_end(union au_vdir_deblk_p *p,
union au_vdir_deblk_p *deblk_end)
{
- if (calc_size(0) <= deblk_end->p - p->p)
+ if (calc_size(0) <= deblk_end->deblk - p->deblk)
return !p->de->de_str.len;
return 1;
}
-static au_vdir_deblk_t *last_deblk(struct au_vdir *vdir)
+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)
{
@@ -81,91 +72,115 @@ unsigned int au_rdhash_est(loff_t sz)
return n;
}
-void au_nhash_init(struct au_nhash *nhash)
+int au_nhash_alloc(struct au_nhash *nhash, unsigned int num_hash, gfp_t gfp)
{
- int i;
- for (i = 0; i < AuSize_NHASH; i++)
- INIT_HLIST_HEAD(nhash->heads + i);
+ struct hlist_head *head;
+ unsigned int u;
+
+ head = kmalloc(sizeof(*nhash->nh_head) * num_hash, 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;
}
-struct au_nhash *au_nhash_new(gfp_t gfp)
+static void au_nhash_wh_do_free(struct hlist_head *head)
{
- struct au_nhash *nhash;
+ struct au_vdir_wh *tpos;
+ struct hlist_node *pos, *node;
- nhash = kmalloc(sizeof(*nhash), gfp);
- if (nhash) {
- au_nhash_init(nhash);
- return nhash;
+ hlist_for_each_entry_safe(tpos, pos, node, head, wh_hash) {
+ /* hlist_del(pos); */
+ kfree(tpos);
}
- return ERR_PTR(-ENOMEM);
}
-void au_nhash_del(struct au_nhash *nhash)
+static void au_nhash_de_do_free(struct hlist_head *head)
{
- au_nhash_fin(nhash);
- kfree(nhash);
+ struct au_vdir_dehstr *tpos;
+ struct hlist_node *pos, *node;
+
+ hlist_for_each_entry_safe(tpos, pos, node, head, hash) {
+ /* hlist_del(pos); */
+ au_cache_free_dehstr(tpos);
+ }
}
-void au_nhash_move(struct au_nhash *dst, struct au_nhash *src)
+static void au_nhash_do_free(struct au_nhash *nhash,
+ void (*free)(struct hlist_head *head))
{
- int i;
+ unsigned int n;
+ struct hlist_head *head;
- AuTraceEnter();
+ n = nhash->nh_num;
+ if (!n)
+ return;
- *dst = *src;
- for (i = 0; i < AuSize_NHASH; i++) {
- struct hlist_head *h;
- h = dst->heads + i;
- if (h->first)
- h->first->pprev = &h->first;
- INIT_HLIST_HEAD(src->heads + i);
- }
- /* smp_mb(); */
+ head = nhash->nh_head;
+ while (n-- > 0)
+ free(head++);
+ kfree(nhash->nh_head);
}
-/* ---------------------------------------------------------------------- */
-
-void au_nhash_fin(struct au_nhash *whlist)
+void au_nhash_wh_free(struct au_nhash *whlist)
{
- int i;
- struct hlist_head *head;
- struct au_vdir_wh *tpos;
- struct hlist_node *pos, *n;
-
- AuTraceEnter();
+ au_nhash_do_free(whlist, au_nhash_wh_do_free);
+}
- for (i = 0; i < AuSize_NHASH; i++) {
- head = whlist->heads + i;
- hlist_for_each_entry_safe(tpos, pos, n, head, wh_hash) {
- /* hlist_del(pos); */
- kfree(tpos);
- }
- }
+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 n, i;
+ int num;
+ unsigned int u, n;
struct hlist_head *head;
struct au_vdir_wh *tpos;
struct hlist_node *pos;
LKTRTrace("limit %d\n", limit);
- n = 0;
- for (i = 0; i < AuSize_NHASH; i++) {
- head = whlist->heads + i;
+ num = 0;
+ n = whlist->nh_num;
+ head = whlist->nh_head;
+ for (u = 0; u < n; u++, head++)
hlist_for_each_entry(tpos, pos, head, wh_hash)
- if (tpos->wh_bindex == btgt && ++n > limit)
+ if (tpos->wh_bindex == btgt && ++num > limit)
return 1;
- }
return 0;
}
-static unsigned int au_name_hash(const unsigned char *name, unsigned int len)
+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 namelen)
{
- return full_name_hash(name, len) % AuSize_NHASH;
+ return str->len == namelen && !memcmp(str->name, name, namelen);
}
/* returns found(true) or not */
@@ -178,11 +193,11 @@ int au_nhash_test_known_wh(struct au_nhash *whlist, char
*name, int namelen)
LKTRTrace("%.*s\n", namelen, name);
- head = whlist->heads + au_name_hash(name, namelen);
+ head = au_name_hash(whlist, name, namelen);
hlist_for_each_entry(tpos, pos, head, wh_hash) {
str = &tpos->wh_str;
LKTRTrace("%.*s\n", str->len, str->name);
- if (str->len == namelen && !memcmp(str->name, name, namelen))
+ if (au_nhash_test_name(str, name, namelen))
return 1;
}
return 0;
@@ -197,6 +212,7 @@ int au_nhash_append_wh(struct au_nhash *whlist, char *name,
int namelen,
struct au_vdir_wh *wh;
LKTRTrace("%.*s\n", namelen, name);
+ AuDebugOn(!whlist->nh_num || !whlist->nh_head);
err = -ENOMEM;
wh = kmalloc(sizeof(*wh) + namelen, GFP_NOFS);
@@ -209,8 +225,7 @@ int au_nhash_append_wh(struct au_nhash *whlist, char *name,
int namelen,
str = &wh->wh_str;
str->len = namelen;
memcpy(str->name, name, namelen);
- hlist_add_head(&wh->wh_hash,
- whlist->heads + au_name_hash(name, namelen));
+ hlist_add_head(&wh->wh_hash, au_name_hash(whlist, name, namelen));
/* smp_mb(); */
out:
@@ -222,24 +237,24 @@ int au_nhash_append_wh(struct au_nhash *whlist, char
*name, int namelen,
void au_vdir_free(struct au_vdir *vdir)
{
- au_vdir_deblk_t **deblk;
+ unsigned char **deblk;
AuTraceEnter();
deblk = vdir->vd_deblk;
- while (vdir->vd_nblk--) {
- kfree(*deblk);
- deblk++;
- }
+ while (vdir->vd_nblk--)
+ kfree(*deblk++);
kfree(vdir->vd_deblk);
au_cache_free_vdir(vdir);
}
static int append_deblk(struct au_vdir *vdir)
{
- int err, sz, i;
- au_vdir_deblk_t **o;
+ int err, sz;
+ unsigned long ul;
+ const unsigned int deblk_sz = vdir->vd_deblk_sz;
union au_vdir_deblk_p p, deblk_end;
+ unsigned char **o;
AuTraceEnter();
@@ -249,13 +264,15 @@ static int append_deblk(struct au_vdir *vdir)
if (unlikely(!o))
goto out;
vdir->vd_deblk = o;
- p.deblk = kmalloc(sizeof(*p.deblk), GFP_NOFS);
+ LKTRTrace("%u\n", deblk_sz);
+ p.deblk = kmalloc(deblk_sz, GFP_NOFS);
+ LKTRTrace("%p\n", p.deblk);
if (p.deblk) {
- i = vdir->vd_nblk++;
- vdir->vd_deblk[i] = p.deblk;
- vdir->vd_last.i = i;
- vdir->vd_last.p.p = p.p;
- deblk_end.deblk = p.deblk + 1;
+ 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);
AuDebugOn(err);
}
@@ -265,7 +282,7 @@ static int append_deblk(struct au_vdir *vdir)
return err;
}
-static struct au_vdir *alloc_vdir(void)
+static struct au_vdir *alloc_vdir(struct file *file)
{
struct au_vdir *vdir;
int err;
@@ -281,6 +298,8 @@ static struct au_vdir *alloc_vdir(void)
goto out_free;
vdir->vd_nblk = 0;
+ /* estimate the apropriate size for deblk */
+ vdir->vd_deblk_sz = au_dir_size(file, /*dentry*/NULL);
vdir->vd_version = 0;
vdir->vd_jiffy = 0;
err = append_deblk(vdir);
@@ -310,12 +329,12 @@ static int reinit_vdir(struct au_vdir *vdir)
vdir->vd_nblk--;
}
p.deblk = vdir->vd_deblk[0];
- deblk_end.deblk = p.deblk + 1;
+ deblk_end.deblk = p.deblk + vdir->vd_deblk_sz;
err = set_deblk_end(&p, &deblk_end);
AuDebugOn(err);
vdir->vd_version = 0;
vdir->vd_jiffy = 0;
- vdir->vd_last.i = 0;
+ vdir->vd_last.ul = 0;
vdir->vd_last.p.deblk = vdir->vd_deblk[0];
/* smp_mb(); */
return err;
@@ -323,24 +342,6 @@ static int reinit_vdir(struct au_vdir *vdir)
/* ---------------------------------------------------------------------- */
-static void free_dehlist(struct au_nhash *dehlist)
-{
- int i;
- struct hlist_head *head;
- struct au_vdir_dehstr *tpos;
- struct hlist_node *pos, *n;
-
- AuTraceEnter();
-
- for (i = 0; i < AuSize_NHASH; i++) {
- head = dehlist->heads + i;
- hlist_for_each_entry_safe(tpos, pos, n, head, hash) {
- /* hlist_del(pos); */
- au_cache_free_dehstr(tpos);
- }
- }
-}
-
/* returns found(true) or not */
static int test_known(struct au_nhash *delist, char *name, int namelen)
{
@@ -351,11 +352,11 @@ static int test_known(struct au_nhash *delist, char
*name, int namelen)
LKTRTrace("%.*s\n", namelen, name);
- head = delist->heads + au_name_hash(name, namelen);
+ head = au_name_hash(delist, name, namelen);
hlist_for_each_entry(tpos, pos, head, hash) {
str = tpos->str;
LKTRTrace("%.*s\n", str->len, str->name);
- if (str->len == namelen && !memcmp(str->name, name, namelen))
+ if (au_nhash_test_name(str, name, namelen))
return 1;
}
return 0;
@@ -365,7 +366,9 @@ static int test_known(struct au_nhash *delist, char *name,
int namelen)
static int append_de(struct au_vdir *vdir, char *name, int namelen, ino_t ino,
unsigned int d_type, struct au_nhash *delist)
{
- int err, sz;
+ 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;
@@ -373,20 +376,20 @@ static int append_de(struct au_vdir *vdir, char *name,
int namelen, ino_t ino,
namelen, name, namelen, (unsigned long)ino, d_type);
p.deblk = last_deblk(vdir);
- deblk_end.deblk = p.deblk + 1;
+ deblk_end.deblk = p.deblk + deblk_sz;
room = &vdir->vd_last.p;
- AuDebugOn(room->p < p.p || deblk_end.p <= room->p
+ AuDebugOn(room->deblk < p.deblk || deblk_end.deblk <= room->deblk
|| !is_deblk_end(room, &deblk_end));
sz = calc_size(namelen);
- if (unlikely(sz > deblk_end.p - room->p)) {
+ 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 + 1;
+ deblk_end.deblk = p.deblk + deblk_sz;
/* smp_mb(); */
- AuDebugOn(room->p != p.p);
+ AuDebugOn(room->deblk != p.deblk);
}
err = -ENOMEM;
@@ -394,8 +397,7 @@ static int append_de(struct au_vdir *vdir, char *name, int
namelen, ino_t ino,
if (unlikely(!dehstr))
goto out;
dehstr->str = &room->de->de_str;
- hlist_add_head(&dehstr->hash,
- delist->heads + au_name_hash(name, namelen));
+ hlist_add_head(&dehstr->hash, au_name_hash(delist, name, namelen));
room->de->de_ino = ino;
room->de->de_type = d_type;
@@ -403,7 +405,7 @@ static int append_de(struct au_vdir *vdir, char *name, int
namelen, ino_t ino,
memcpy(room->de->de_str.name, name, namelen);
err = 0;
- room->p += sz;
+ room->deblk += sz;
if (unlikely(set_deblk_end(room, &deblk_end)))
err = append_deblk(vdir);
/* smp_mb(); */
@@ -488,8 +490,8 @@ static int au_wh_ino(struct super_block *sb, aufs_bindex_t
bindex, ino_t h_ino,
struct fillvdir_arg {
struct file *file;
struct au_vdir *vdir;
- struct au_nhash *delist;
- struct au_nhash *whlist;
+ struct au_nhash delist;
+ struct au_nhash whlist;
aufs_bindex_t bindex;
unsigned int flags;
int err;
@@ -500,7 +502,6 @@ static int fillvdir(void *__arg, const char *__name, int
namelen, loff_t offset,
{
struct fillvdir_arg *arg = __arg;
char *name = (void *)__name;
- aufs_bindex_t bindex, bend;
struct super_block *sb;
ino_t ino;
@@ -508,38 +509,35 @@ static int fillvdir(void *__arg, const char *__name, int
namelen, loff_t offset,
namelen, name, namelen, (unsigned long long)h_ino, d_type);
sb = arg->file->f_dentry->d_sb;
- bend = arg->bindex;
arg->err = 0;
au_fset_fillvdir(arg->flags, CALLED);
/* smp_mb(); */
if (namelen <= AUFS_WH_PFX_LEN
|| memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) {
- for (bindex = 0; bindex < bend; bindex++)
- if (test_known(arg->delist + bindex, name, namelen)
- || au_nhash_test_known_wh(arg->whlist + bindex,
- name, namelen))
- goto out; /* already exists or whiteouted */
+ if (test_known(&arg->delist, name, namelen)
+ || au_nhash_test_known_wh(&arg->whlist, name, namelen))
+ goto out; /* already exists or whiteouted */
ino = 1; /* why does gcc warns? */
- arg->err = au_ino(sb, bend, h_ino, d_type, &ino);
+ arg->err = au_ino(sb, arg->bindex, h_ino, d_type, &ino);
if (!arg->err)
arg->err = append_de(arg->vdir, name, namelen, ino,
- d_type, arg->delist + bend);
+ d_type, &arg->delist);
} else {
name += AUFS_WH_PFX_LEN;
namelen -= AUFS_WH_PFX_LEN;
- for (bindex = 0; bindex < bend; bindex++)
- if (au_nhash_test_known_wh(arg->whlist + bend, name,
- namelen))
- goto out; /* already whiteouted */
+ if (au_nhash_test_known_wh(&arg->whlist, name, namelen))
+ goto out; /* already whiteouted */
ino = 1; /* dummy */
if (au_ftest_fillvdir(arg->flags, SHWH))
- arg->err = au_wh_ino(sb, bend, h_ino, d_type, &ino);
+ arg->err = au_wh_ino(sb, arg->bindex, h_ino, d_type,
+ &ino);
if (!arg->err)
arg->err = au_nhash_append_wh
- (arg->whlist + bend, name, namelen, ino, d_type,
- bend, au_ftest_fillvdir(arg->flags, SHWH));
+ (&arg->whlist, name, namelen, ino, d_type,
+ arg->bindex,
+ au_ftest_fillvdir(arg->flags, SHWH));
}
out:
@@ -551,8 +549,7 @@ static int fillvdir(void *__arg, const char *__name, int
namelen, loff_t offset,
}
static int au_handle_shwh(struct super_block *sb, struct au_vdir *vdir,
- aufs_bindex_t bstart, aufs_bindex_t bend,
- struct au_nhash *_whlist, struct au_nhash *_delist)
+ struct au_nhash *whlist, struct au_nhash *delist)
{
#ifdef CONFIG_AUFS_SHWH
int err, i;
@@ -573,24 +570,18 @@ static int au_handle_shwh(struct super_block *sb, struct
au_vdir *vdir,
goto out;
err = 0;
+ nh = whlist->nh_num;
memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN);
p += AUFS_WH_PFX_LEN;
- for (bindex = bstart; !err && bindex <= bend; bindex++) {
- whlist = _whlist + bindex;
- delist = _delist + bindex;
-
- for (i = 0; i < AuSize_NHASH; i++) {
- head = whlist->heads + i;
- hlist_for_each_entry_safe(tpos, pos, n, head, wh_hash) {
- destr = &tpos->wh_str;
- memcpy(p, destr->name, destr->len);
- err = append_de(vdir, o,
- destr->len + AUFS_WH_PFX_LEN,
- tpos->wh_ino, tpos->wh_type,
- delist);
- if (unlikely(err))
- break;
- }
+ for (u = 0; u < nh; u++) {
+ head = whlist->nh_head + u;
+ hlist_for_each_entry_safe(tpos, pos, n, head, wh_hash) {
+ destr = &tpos->wh_str;
+ memcpy(p, destr->name, destr->len);
+ err = append_de(vdir, o, destr->len + AUFS_WH_PFX_LEN,
+ tpos->wh_ino, tpos->wh_type, delist);
+ if (unlikely(err))
+ break;
}
}
@@ -607,30 +598,27 @@ static int au_handle_shwh(struct super_block *sb, struct
au_vdir *vdir,
static int au_do_read_vdir(struct fillvdir_arg *arg)
{
int err;
- unsigned int mnt_flags;
+ unsigned int rdhash, mnt_flags;
loff_t offset;
aufs_bindex_t bend, bindex, bstart;
unsigned char dlgt, shwh;
struct super_block *sb;
- struct file *hf;
+ struct file *hf, *file;
AuTraceEnter();
err = -ENOMEM;
- bend = au_fbend(arg->file);
- arg->delist = kmalloc(sizeof(*arg->delist) * (bend + 1), GFP_NOFS);
- if (unlikely(!arg->delist))
+ file = arg->file;
+ rdhash = au_rdhash_est(au_dir_size(file, /*dentry*/NULL));
+ err = au_nhash_alloc(&arg->delist, rdhash, GFP_NOFS);
+ if (unlikely(err))
goto out;
- arg->whlist = kmalloc(sizeof(*arg->whlist) * (bend + 1), GFP_NOFS);
- if (unlikely(!arg->whlist))
+ err = au_nhash_alloc(&arg->whlist, rdhash, GFP_NOFS);
+ if (unlikely(err))
goto out_delist;
- err = 0;
- for (bindex = 0; bindex <= bend; bindex++) {
- au_nhash_init(arg->delist + bindex);
- au_nhash_init(arg->whlist + bindex);
- }
- sb = arg->file->f_dentry->d_sb;
+ err = 0;
+ sb = file->f_dentry->d_sb;
mnt_flags = au_mntflags(sb);
dlgt = !!au_test_dlgt(mnt_flags);
arg->flags = 0;
@@ -639,9 +627,10 @@ static int au_do_read_vdir(struct fillvdir_arg *arg)
shwh = 1;
au_fset_fillvdir(arg->flags, SHWH);
}
- bstart = au_fbstart(arg->file);
+ bstart = au_fbstart(file);
+ bend = au_fbend(file);
for (bindex = bstart; !err && bindex <= bend; bindex++) {
- hf = au_h_fptr(arg->file, bindex);
+ hf = au_h_fptr(file, bindex);
if (!hf)
continue;
@@ -661,17 +650,12 @@ static int au_do_read_vdir(struct fillvdir_arg *arg)
}
if (!err && shwh)
- err = au_handle_shwh(sb, arg->vdir, bstart, bend, arg->whlist,
- arg->delist);
+ err = au_handle_shwh(sb, arg->vdir, &arg->whlist, &arg->delist);
- for (bindex = bstart; bindex <= bend; bindex++) {
- free_dehlist(arg->delist + bindex);
- au_nhash_fin(arg->whlist + bindex);
- }
- kfree(arg->whlist);
+ au_nhash_wh_free(&arg->whlist);
out_delist:
- kfree(arg->delist);
+ au_nhash_de_free(&arg->delist);
out:
AuTraceErr(err);
return err;
@@ -705,7 +689,7 @@ static int read_vdir(struct file *file, int may_read)
if (!vdir) {
AuDebugOn(au_fvdir_cache(file));
do_read = 1;
- vdir = alloc_vdir();
+ vdir = alloc_vdir(file);
err = PTR_ERR(vdir);
if (IS_ERR(vdir))
goto out;
@@ -733,7 +717,7 @@ static int read_vdir(struct file *file, int may_read)
/* todo: necessary? */
/* file->f_pos = 0; */
vdir->vd_version = inode->i_version;
- vdir->vd_last.i = 0;
+ vdir->vd_last.ul = 0;
vdir->vd_last.p.deblk = vdir->vd_deblk[0];
if (allocated)
au_set_ivdir(inode, allocated);
@@ -747,14 +731,17 @@ static int read_vdir(struct file *file, int may_read)
static int copy_vdir(struct au_vdir *tgt, struct au_vdir *src)
{
- int err, i, rerr, n;
+ int err, rerr;
+ unsigned long ul, n;
+ const unsigned int deblk_sz = src->vd_deblk_sz;
AuTraceEnter();
AuDebugOn(tgt->vd_nblk != 1);
err = -ENOMEM;
if (tgt->vd_nblk < src->vd_nblk) {
- au_vdir_deblk_t **p;
+ unsigned char **p;
+
p = au_kzrealloc(tgt->vd_deblk, sizeof(*p) * tgt->vd_nblk,
sizeof(*p) * src->vd_nblk, GFP_NOFS);
if (unlikely(!p))
@@ -762,22 +749,32 @@ static int copy_vdir(struct au_vdir *tgt, struct au_vdir
*src)
tgt->vd_deblk = p;
}
- tgt->vd_nblk = src->vd_nblk;
- n = src->vd_nblk;
- memcpy(tgt->vd_deblk[0], src->vd_deblk[0], AuSize_DEBLK);
- /* tgt->vd_last.i = 0; */
- /* tgt->vd_last.p.deblk = tgt->vd_deblk[0]; */
+ 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;
- for (i = 1; i < n; i++) {
- tgt->vd_deblk[i] = kmalloc(AuSize_DEBLK, GFP_NOFS);
- if (tgt->vd_deblk[i])
- memcpy(tgt->vd_deblk[i], src->vd_deblk[i],
- AuSize_DEBLK);
- else
+ n = src->vd_nblk;
+ for (ul = 0; 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 */
@@ -809,7 +806,7 @@ int au_vdir_init(struct file *file)
allocated = NULL;
vdir_cache = au_fvdir_cache(file);
if (!vdir_cache) {
- vdir_cache = alloc_vdir();
+ vdir_cache = alloc_vdir(file);
err = PTR_ERR(vdir_cache);
if (IS_ERR(vdir_cache))
goto out;
@@ -839,20 +836,22 @@ 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.i];
- offset = vdir->vd_last.p.p - p.p;
- offset += sizeof(*p.deblk) * vdir->vd_last.i;
+ 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)
{
- int valid, i, n;
- struct dentry *dentry;
- struct au_vdir *vdir_cache;
+ 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;
+ struct dentry *dentry;
dentry = file->f_dentry;
LKTRTrace("%.*s, pos %lld\n", AuDLNPair(dentry), file->f_pos);
@@ -865,32 +864,34 @@ static int seek_vdir(struct file *file)
if (file->f_pos == offset)
goto out;
- vdir_cache->vd_last.i = 0;
+ vdir_cache->vd_last.ul = 0;
vdir_cache->vd_last.p.deblk = vdir_cache->vd_deblk[0];
if (!file->f_pos)
goto out;
valid = 0;
- i = file->f_pos / AuSize_DEBLK;
- LKTRTrace("i %d\n", i);
- if (i >= vdir_cache->vd_nblk)
+ deblk_sz = vdir_cache->vd_deblk_sz;
+ ul = file->f_pos / deblk_sz;
+ LKTRTrace("ul %lu\n", ul);
+ if (ul >= vdir_cache->vd_nblk)
goto out;
n = vdir_cache->vd_nblk;
- for (; i < n; i++) {
- p.deblk = vdir_cache->vd_deblk[i];
- deblk_end.deblk = p.deblk + 1;
- offset = i;
- offset *= AuSize_DEBLK;
+ 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 < file->f_pos) {
- int l;
+ unsigned int l;
+
l = calc_size(p.de->de_str.len);
offset += l;
- p.p += l;
+ p.deblk += l;
}
if (!is_deblk_end(&p, &deblk_end)) {
valid = 1;
- vdir_cache->vd_last.i = i;
+ vdir_cache->vd_last.ul = ul;
vdir_cache->vd_last.p = p;
break;
}
@@ -904,7 +905,8 @@ static int seek_vdir(struct file *file)
int au_vdir_fill_de(struct file *file, void *dirent, filldir_t filldir)
{
- int err, l;
+ int err;
+ unsigned int l, deblk_sz;
struct dentry *dentry;
struct au_vdir *vdir_cache;
struct au_vdir_de *de;
@@ -918,9 +920,10 @@ int au_vdir_fill_de(struct file *file, void *dirent,
filldir_t filldir)
if (!seek_vdir(file))
return 0;
+ deblk_sz = vdir_cache->vd_deblk_sz;
while (1) {
- deblk_end.deblk
- = vdir_cache->vd_deblk[vdir_cache->vd_last.i] + 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;
LKTRTrace("%.*s, off%lld, i%lu, dt%d\n",
@@ -937,15 +940,14 @@ int au_vdir_fill_de(struct file *file, void *dirent,
filldir_t filldir)
}
l = calc_size(de->de_str.len);
- vdir_cache->vd_last.p.p += l;
+ vdir_cache->vd_last.p.deblk += l;
file->f_pos += l;
}
- if (vdir_cache->vd_last.i < vdir_cache->vd_nblk - 1) {
- vdir_cache->vd_last.i++;
+ 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.i];
- file->f_pos = sizeof(*vdir_cache->vd_last.p.deblk)
- * vdir_cache->vd_last.i;
+ = vdir_cache->vd_deblk[vdir_cache->vd_last.ul];
+ file->f_pos = deblk_sz * vdir_cache->vd_last.ul;
continue;
}
break;
diff --git a/fs/aufs/whout.c b/fs/aufs/whout.c
index 8521cc2..6462275 100644
--- a/fs/aufs/whout.c
+++ b/fs/aufs/whout.c
@@ -942,7 +942,8 @@ struct dentry *au_wh_create(struct dentry *dentry,
aufs_bindex_t bindex,
static int del_wh_children(struct dentry *h_dentry, struct au_nhash *whlist,
aufs_bindex_t bindex, struct au_ndx *ndx)
{
- int err, i;
+ int err;
+ unsigned long ul, n;
struct qstr wh_name;
char *p;
struct inode *h_inode;
@@ -965,8 +966,9 @@ static int del_wh_children(struct dentry *h_dentry, struct
au_nhash *whlist,
/* already checked by au_test_h_perm(). */
err = 0;
- for (i = 0; !err && i < AuSize_NHASH; i++) {
- head = whlist->heads + i;
+ n = whlist->nh_num;
+ head = whlist->nh_head;
+ for (ul = 0; !err && ul < n; ul++, head++) {
hlist_for_each_entry(tpos, pos, head, wh_hash) {
if (tpos->wh_bindex != bindex)
continue;
@@ -1091,18 +1093,42 @@ int au_whtmp_rmdir(struct inode *dir, aufs_bindex_t
bindex,
return err;
}
-static void au_whtmp_rmdir_free_args(struct au_whtmp_rmdir_args *args)
+struct au_whtmp_rmdir *au_whtmp_rmdir_alloc(struct super_block *sb, gfp_t gfp)
+{
+ struct au_whtmp_rmdir *whtmp;
+ int err;
+
+ whtmp = kmalloc(sizeof(*whtmp), gfp);
+ if (unlikely(!whtmp)) {
+ whtmp = ERR_PTR(-ENOMEM);
+ goto out;
+ }
+
+ whtmp->dir = NULL;
+ whtmp->wh_dentry = NULL;
+ /* no estimation for dir size */
+ err = au_nhash_alloc(&whtmp->whlist, AUFS_RDHASH_DEF, gfp);
+ if (unlikely(err)) {
+ kfree(whtmp);
+ whtmp = ERR_PTR(err);
+ }
+
+ out:
+ return whtmp;
+}
+
+void au_whtmp_rmdir_free(struct au_whtmp_rmdir *whtmp)
{
- au_nhash_fin(&args->whlist);
- dput(args->wh_dentry);
- iput(args->dir);
- kfree(args);
+ dput(whtmp->wh_dentry);
+ iput(whtmp->dir);
+ au_nhash_wh_free(&whtmp->whlist);
+ kfree(whtmp);
}
static void call_rmdir_whtmp(void *args)
{
int err;
- struct au_whtmp_rmdir_args *a = args;
+ struct au_whtmp_rmdir *a = args;
struct super_block *sb;
struct dentry *h_parent;
struct inode *h_dir;
@@ -1139,14 +1165,13 @@ static void call_rmdir_whtmp(void *args)
/* vfsub_i_unlock(a->dir); */
au_nwt_done(&au_sbi(sb)->si_nowait);
si_read_unlock(sb);
- au_whtmp_rmdir_free_args(a);
+ au_whtmp_rmdir_free(a);
if (unlikely(err))
AuIOErr("err %d\n", err);
}
void au_whtmp_kick_rmdir(struct inode *dir, aufs_bindex_t bindex,
- struct dentry *wh_dentry, struct au_nhash *whlist,
- struct au_whtmp_rmdir_args *args)
+ struct dentry *wh_dentry, struct au_whtmp_rmdir *args)
{
int wkq_err;
@@ -1157,12 +1182,10 @@ void au_whtmp_kick_rmdir(struct inode *dir,
aufs_bindex_t bindex,
args->dir = au_igrab(dir);
args->bindex = bindex;
args->wh_dentry = dget(wh_dentry);
- au_nhash_init(&args->whlist);
- au_nhash_move(&args->whlist, whlist);
wkq_err = au_wkq_nowait(call_rmdir_whtmp, args, dir->i_sb, /*dlgt*/0);
if (unlikely(wkq_err)) {
AuWarn("rmdir error %.*s (%d), ignored\n",
AuDLNPair(wh_dentry), wkq_err);
- au_whtmp_rmdir_free_args(args);
+ au_whtmp_rmdir_free(args);
}
}
diff --git a/fs/aufs/whout.h b/fs/aufs/whout.h
index 056ca13..9f3ab25 100644
--- a/fs/aufs/whout.h
+++ b/fs/aufs/whout.h
@@ -70,19 +70,20 @@ struct dentry *au_wh_create(struct dentry *dentry,
aufs_bindex_t bindex,
struct dentry *h_parent, struct au_ndx *ndx);
/* real rmdir the whiteout-ed dir */
-struct au_whtmp_rmdir_args {
+struct au_whtmp_rmdir {
struct inode *dir;
aufs_bindex_t bindex;
struct dentry *wh_dentry;
struct au_nhash whlist;
};
+struct au_whtmp_rmdir *au_whtmp_rmdir_alloc(struct super_block *sb, gfp_t gfp);
+void au_whtmp_rmdir_free(struct au_whtmp_rmdir *whtmp);
struct au_nhash;
int au_whtmp_rmdir(struct inode *dir, aufs_bindex_t bindex,
struct dentry *wh_dentry, struct au_nhash *whlist);
void au_whtmp_kick_rmdir(struct inode *dir, aufs_bindex_t bindex,
- struct dentry *wh_dentry, struct au_nhash *whlist,
- struct au_whtmp_rmdir_args *args);
+ struct dentry *wh_dentry, struct au_whtmp_rmdir *args);
/* ---------------------------------------------------------------------- */
--
1.6.1.284.g5dc13
------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now. http://p.sf.net/sfu/bobj-july