summaryrefslogtreecommitdiff
path: root/fs/aufs/module.h
diff options
context:
space:
mode:
Diffstat (limited to 'fs/aufs/module.h')
-rw-r--r--fs/aufs/module.h63
1 files changed, 59 insertions, 4 deletions
diff --git a/fs/aufs/module.h b/fs/aufs/module.h
index 1383e3da9..681dc75f5 100644
--- a/fs/aufs/module.h
+++ b/fs/aufs/module.h
@@ -12,6 +12,7 @@
#ifdef __KERNEL__
#include <linux/slab.h>
+#include "debug.h"
struct path;
struct seq_file;
@@ -38,7 +39,7 @@ AuStubVoid(au_procfs_fin, void);
/* ---------------------------------------------------------------------- */
-/* kmem cache */
+/* kmem cache and delayed free */
enum {
AuCache_DINFO,
AuCache_ICNTNR,
@@ -49,19 +50,54 @@ enum {
AuCache_Last
};
+enum {
+ AU_DFREE_KFREE,
+ AU_DFREE_FREE_PAGE,
+ AU_DFREE_Last
+};
+
+struct au_cache {
+ struct kmem_cache *cache;
+ struct llist_head llist; /* delayed free */
+};
+
+/*
+ * in order to reduce the cost of the internal timer, consolidate all the
+ * delayed free works into a single delayed_work.
+ */
+struct au_dfree {
+ struct au_cache cache[AuCache_Last];
+ struct llist_head llist[AU_DFREE_Last];
+ struct delayed_work dwork;
+};
+
+extern struct au_dfree au_dfree;
+
#define AuCacheFlags (SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD)
#define AuCache(type) KMEM_CACHE(type, AuCacheFlags)
#define AuCacheCtor(type, ctor) \
kmem_cache_create(#type, sizeof(struct type), \
__alignof__(struct type), AuCacheFlags, ctor)
-extern struct kmem_cache *au_cachep[];
+#define AU_DFREE_DELAY msecs_to_jiffies(10)
+#define AU_DFREE_BODY(lnode, llist) do { \
+ if (llist_add(lnode, llist)) \
+ schedule_delayed_work(&au_dfree.dwork, \
+ AU_DFREE_DELAY); \
+ } while (0)
+#define AU_CACHE_DFREE_FUNC(name, idx, lnode) \
+ void au_cache_dfree_##name(struct au_##name *p) \
+ { \
+ struct au_cache *cp = au_dfree.cache + AuCache_##idx; \
+ AU_DFREE_BODY(&p->lnode, &cp->llist); \
+ }
#define AuCacheFuncs(name, index) \
static inline struct au_##name *au_cache_alloc_##name(void) \
-{ return kmem_cache_alloc(au_cachep[AuCache_##index], GFP_NOFS); } \
+{ return kmem_cache_alloc(au_dfree.cache[AuCache_##index].cache, GFP_NOFS); } \
static inline void au_cache_free_##name(struct au_##name *p) \
-{ kmem_cache_free(au_cachep[AuCache_##index], p); }
+{ kmem_cache_free(au_dfree.cache[AuCache_##index].cache, p); } \
+void au_cache_dfree_##name(struct au_##name *p)
AuCacheFuncs(dinfo, DINFO);
AuCacheFuncs(icntnr, ICNTNR);
@@ -72,5 +108,24 @@ AuCacheFuncs(vdir_dehstr, DEHSTR);
AuCacheFuncs(hnotify, HNOTIFY);
#endif
+static inline void au_delayed_kfree(const void *p)
+{
+ AuDebugOn(!p);
+ AuDebugOn(ksize(p) < sizeof(struct llist_node));
+
+ AU_DFREE_BODY((void *)p, au_dfree.llist + AU_DFREE_KFREE);
+}
+
+/* cast only */
+static inline void au_free_page(void *p)
+{
+ free_page((unsigned long)p);
+}
+
+static inline void au_delayed_free_page(unsigned long addr)
+{
+ AU_DFREE_BODY((void *)addr, au_dfree.llist + AU_DFREE_FREE_PAGE);
+}
+
#endif /* __KERNEL__ */
#endif /* __AUFS_MODULE_H__ */