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.c60
1 files changed, 52 insertions, 8 deletions
diff --git a/fs/aufs/module.c b/fs/aufs/module.c
index ede9a232a..5092b4bd6 100644
--- a/fs/aufs/module.c
+++ b/fs/aufs/module.c
@@ -10,13 +10,57 @@
#include <linux/seq_file.h>
#include "aufs.h"
-void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp)
+/* shrinkable realloc */
+void *au_krealloc(void *p, unsigned int new_sz, gfp_t gfp, int may_shrink)
{
- if (new_sz <= nused)
- return p;
+ size_t sz;
+ int diff;
+
+ sz = 0;
+ diff = -1;
+ if (p) {
+#if 0 /* unused */
+ if (!new_sz) {
+ au_delayed_kfree(p);
+ p = NULL;
+ goto out;
+ }
+#else
+ AuDebugOn(!new_sz);
+#endif
+ sz = ksize(p);
+ diff = au_kmidx_sub(sz, new_sz);
+ }
+ if (sz && !diff)
+ goto out;
+
+ if (sz < new_sz)
+ /* expand or SLOB */
+ p = krealloc(p, new_sz, gfp);
+ else if (new_sz < sz && may_shrink) {
+ /* shrink */
+ void *q;
+
+ q = kmalloc(new_sz, gfp);
+ if (q) {
+ if (p) {
+ memcpy(q, p, new_sz);
+ au_delayed_kfree(p);
+ }
+ p = q;
+ } else
+ p = NULL;
+ }
- p = krealloc(p, new_sz, gfp);
- if (p)
+out:
+ return p;
+}
+
+void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp,
+ int may_shrink)
+{
+ p = au_krealloc(p, new_sz, gfp, may_shrink);
+ if (p && new_sz > nused)
memset(p + nused, 0, new_sz - nused);
return p;
}
@@ -38,9 +82,9 @@ static void au_do_dfree(struct work_struct *work __maybe_unused)
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); \
+ struct au_##name *p \
+ = llist_entry(node, struct au_##name, \
+ lnode); \
next = llist_next(node); \
au_cache_free_##name(p); \
} \