summaryrefslogtreecommitdiff
path: root/fs/aufs/module.h
blob: 681dc75f599b0ec366232b9b1165a4a3ac6deee3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/*
 * Copyright (C) 2005-2016 Junjiro R. Okajima
 */

/*
 * module initialization and module-global
 */

#ifndef __AUFS_MODULE_H__
#define __AUFS_MODULE_H__

#ifdef __KERNEL__

#include <linux/slab.h>
#include "debug.h"

struct path;
struct seq_file;

/* module parameters */
extern int sysaufs_brs;
extern bool au_userns;

/* ---------------------------------------------------------------------- */

extern int au_dir_roflags;

void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp);
int au_seq_path(struct seq_file *seq, struct path *path);

#ifdef CONFIG_PROC_FS
/* procfs.c */
int __init au_procfs_init(void);
void au_procfs_fin(void);
#else
AuStubInt0(au_procfs_init, void);
AuStubVoid(au_procfs_fin, void);
#endif

/* ---------------------------------------------------------------------- */

/* kmem cache and delayed free */
enum {
	AuCache_DINFO,
	AuCache_ICNTNR,
	AuCache_FINFO,
	AuCache_VDIR,
	AuCache_DEHSTR,
	AuCache_HNOTIFY, /* must be last */
	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)

#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_dfree.cache[AuCache_##index].cache, GFP_NOFS); } \
static inline void au_cache_free_##name(struct au_##name *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);
AuCacheFuncs(finfo, FINFO);
AuCacheFuncs(vdir, VDIR);
AuCacheFuncs(vdir_dehstr, DEHSTR);
#ifdef CONFIG_AUFS_HNOTIFY
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__ */