summaryrefslogtreecommitdiff
path: root/fs/aufs/module.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/aufs/module.c')
-rw-r--r--fs/aufs/module.c102
1 files changed, 84 insertions, 18 deletions
diff --git a/fs/aufs/module.c b/fs/aufs/module.c
index 88f8f4123..ede9a232a 100644
--- a/fs/aufs/module.c
+++ b/fs/aufs/module.c
@@ -22,17 +22,64 @@ void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp)
}
/* ---------------------------------------------------------------------- */
-
/*
* aufs caches
*/
-struct kmem_cache *au_cachep[AuCache_Last] = {
- [0] = NULL
-};
+
+struct au_dfree au_dfree;
+
+/* delayed free */
+static void au_do_dfree(struct work_struct *work __maybe_unused)
+{
+ struct llist_head *head;
+ struct llist_node *node, *next;
+
+#define AU_CACHE_DFREE_DO_BODY(name, idx, lnode) do { \
+ head = &au_dfree.cache[AuCache_##idx].llist; \
+ node = llist_del_all(head); \
+ for (; node; node = next) { \
+ struct au_##name *p = \
+ p = llist_entry(node, struct au_##name, \
+ lnode); \
+ next = llist_next(node); \
+ au_cache_free_##name(p); \
+ } \
+ } while (0)
+
+ AU_CACHE_DFREE_DO_BODY(dinfo, DINFO, di_lnode);
+ AU_CACHE_DFREE_DO_BODY(icntnr, ICNTNR, lnode);
+ AU_CACHE_DFREE_DO_BODY(finfo, FINFO, fi_lnode);
+ AU_CACHE_DFREE_DO_BODY(vdir, VDIR, vd_lnode);
+ AU_CACHE_DFREE_DO_BODY(vdir_dehstr, DEHSTR, lnode);
+#ifdef CONFIG_AUFS_HNOTIFY
+ AU_CACHE_DFREE_DO_BODY(hnotify, HNOTIFY, hn_lnode);
+#endif
+
+#define AU_DFREE_DO_BODY(llist, func) do { \
+ node = llist_del_all(llist); \
+ for (; node; node = next) { \
+ next = llist_next(node); \
+ func(node); \
+ } \
+ } while (0)
+
+ AU_DFREE_DO_BODY(au_dfree.llist + AU_DFREE_KFREE, kfree);
+ AU_DFREE_DO_BODY(au_dfree.llist + AU_DFREE_FREE_PAGE, au_free_page);
+
+#undef AU_CACHE_DFREE_DO_BODY
+#undef AU_DFREE_DO_BODY
+}
+
+AU_CACHE_DFREE_FUNC(dinfo, DINFO, di_lnode);
+AU_CACHE_DFREE_FUNC(icntnr, ICNTNR, lnode);
+AU_CACHE_DFREE_FUNC(finfo, FINFO, fi_lnode);
+AU_CACHE_DFREE_FUNC(vdir, VDIR, vd_lnode);
+AU_CACHE_DFREE_FUNC(vdir_dehstr, DEHSTR, lnode);
static void au_cache_fin(void)
{
int i;
+ struct au_cache *cp;
/*
* Make sure all delayed rcu free inodes are flushed before we
@@ -42,27 +89,33 @@ static void au_cache_fin(void)
/* excluding AuCache_HNOTIFY */
BUILD_BUG_ON(AuCache_HNOTIFY + 1 != AuCache_Last);
+ flush_delayed_work(&au_dfree.dwork);
for (i = 0; i < AuCache_HNOTIFY; i++) {
- kmem_cache_destroy(au_cachep[i]);
- au_cachep[i] = NULL;
+ cp = au_dfree.cache + i;
+ AuDebugOn(!llist_empty(&cp->llist));
+ kmem_cache_destroy(cp->cache);
+ cp->cache = NULL;
}
}
static int __init au_cache_init(void)
{
- au_cachep[AuCache_DINFO] = AuCacheCtor(au_dinfo, au_di_init_once);
- if (au_cachep[AuCache_DINFO])
+ struct au_cache *cp;
+
+ cp = au_dfree.cache;
+ cp[AuCache_DINFO].cache = AuCacheCtor(au_dinfo, au_di_init_once);
+ if (cp[AuCache_DINFO].cache)
/* SLAB_DESTROY_BY_RCU */
- au_cachep[AuCache_ICNTNR] = AuCacheCtor(au_icntnr,
- au_icntnr_init_once);
- if (au_cachep[AuCache_ICNTNR])
- au_cachep[AuCache_FINFO] = AuCacheCtor(au_finfo,
- au_fi_init_once);
- if (au_cachep[AuCache_FINFO])
- au_cachep[AuCache_VDIR] = AuCache(au_vdir);
- if (au_cachep[AuCache_VDIR])
- au_cachep[AuCache_DEHSTR] = AuCache(au_vdir_dehstr);
- if (au_cachep[AuCache_DEHSTR])
+ cp[AuCache_ICNTNR].cache = AuCacheCtor(au_icntnr,
+ au_icntnr_init_once);
+ if (cp[AuCache_ICNTNR].cache)
+ cp[AuCache_FINFO].cache = AuCacheCtor(au_finfo,
+ au_fi_init_once);
+ if (cp[AuCache_FINFO].cache)
+ cp[AuCache_VDIR].cache = AuCache(au_vdir);
+ if (cp[AuCache_VDIR].cache)
+ cp[AuCache_DEHSTR].cache = AuCache(au_vdir_dehstr);
+ if (cp[AuCache_DEHSTR].cache)
return 0;
au_cache_fin();
@@ -124,6 +177,7 @@ static int __init aufs_init(void)
{
int err, i;
char *p;
+ struct au_cache *cp;
p = au_esc_chars;
for (i = 1; i <= ' '; i++)
@@ -138,6 +192,16 @@ static int __init aufs_init(void)
for (i = 0; i < AuIop_Last; i++)
aufs_iop_nogetattr[i].getattr = NULL;
+ /* First, initialize au_dfree */
+ for (i = 0; i < AuCache_Last; i++) { /* including hnotify */
+ cp = au_dfree.cache + i;
+ cp->cache = NULL;
+ init_llist_head(&cp->llist);
+ }
+ for (i = 0; i < AU_DFREE_Last; i++)
+ init_llist_head(au_dfree.llist + i);
+ INIT_DELAYED_WORK(&au_dfree.dwork, au_do_dfree);
+
au_sbilist_init();
sysaufs_brs_init();
au_debug_init();
@@ -188,6 +252,7 @@ out_procfs:
out_sysaufs:
sysaufs_fin();
au_dy_fin();
+ flush_delayed_work(&au_dfree.dwork);
out:
return err;
}
@@ -203,6 +268,7 @@ static void __exit aufs_exit(void)
au_procfs_fin();
sysaufs_fin();
au_dy_fin();
+ flush_delayed_work(&au_dfree.dwork);
}
module_init(aufs_init);