]> git.proxmox.com Git - mirror_ubuntu-focal-kernel.git/blame - fs/aufs/lcnt.h
UBUNTU: SAUCE: Update aufs to 5.4.3 20200302
[mirror_ubuntu-focal-kernel.git] / fs / aufs / lcnt.h
CommitLineData
a3a49a17
SF
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
e4a3f096 3 * Copyright (C) 2018-2020 Junjiro R. Okajima
a3a49a17
SF
4 *
5 * This program, aufs is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19/*
20 * simple long counter wrapper
21 */
22
23#ifndef __AUFS_LCNT_H__
24#define __AUFS_LCNT_H__
25
26#ifdef __KERNEL__
27
28#include "debug.h"
29
30#define AuLCntATOMIC 1
31#define AuLCntPCPUCNT 2
32/*
33 * why does percpu_refcount require extra synchronize_rcu()s in
34 * au_br_do_free()
35 */
36#define AuLCntPCPUREF 3
37
38/* #define AuLCntChosen AuLCntATOMIC */
39#define AuLCntChosen AuLCntPCPUCNT
40/* #define AuLCntChosen AuLCntPCPUREF */
41
42#if AuLCntChosen == AuLCntATOMIC
43#include <linux/atomic.h>
44
45typedef atomic_long_t au_lcnt_t;
46
47static inline int au_lcnt_init(au_lcnt_t *cnt, void *release __maybe_unused)
48{
49 atomic_long_set(cnt, 0);
50 return 0;
51}
52
53static inline void au_lcnt_wait_for_fin(au_lcnt_t *cnt __maybe_unused)
54{
55 /* empty */
56}
57
58static inline void au_lcnt_fin(au_lcnt_t *cnt __maybe_unused,
59 int do_sync __maybe_unused)
60{
61 /* empty */
62}
63
64static inline void au_lcnt_inc(au_lcnt_t *cnt)
65{
66 atomic_long_inc(cnt);
67}
68
69static inline void au_lcnt_dec(au_lcnt_t *cnt)
70{
71 atomic_long_dec(cnt);
72}
73
74static inline long au_lcnt_read(au_lcnt_t *cnt, int do_rev __maybe_unused)
75{
76 return atomic_long_read(cnt);
77}
78#endif
79
80#if AuLCntChosen == AuLCntPCPUCNT
81#include <linux/percpu_counter.h>
82
83typedef struct percpu_counter au_lcnt_t;
84
85static inline int au_lcnt_init(au_lcnt_t *cnt, void *release __maybe_unused)
86{
87 return percpu_counter_init(cnt, 0, GFP_NOFS);
88}
89
90static inline void au_lcnt_wait_for_fin(au_lcnt_t *cnt __maybe_unused)
91{
92 /* empty */
93}
94
95static inline void au_lcnt_fin(au_lcnt_t *cnt, int do_sync __maybe_unused)
96{
97 percpu_counter_destroy(cnt);
98}
99
100static inline void au_lcnt_inc(au_lcnt_t *cnt)
101{
102 percpu_counter_inc(cnt);
103}
104
105static inline void au_lcnt_dec(au_lcnt_t *cnt)
106{
107 percpu_counter_dec(cnt);
108}
109
110static inline long au_lcnt_read(au_lcnt_t *cnt, int do_rev __maybe_unused)
111{
112 s64 n;
113
114 n = percpu_counter_sum(cnt);
115 BUG_ON(n < 0);
116 if (LONG_MAX != LLONG_MAX
117 && n > LONG_MAX)
118 AuWarn1("%s\n", "wrap-around");
119
120 return n;
121}
122#endif
123
124#if AuLCntChosen == AuLCntPCPUREF
125#include <linux/percpu-refcount.h>
126
127typedef struct percpu_ref au_lcnt_t;
128
129static inline int au_lcnt_init(au_lcnt_t *cnt, percpu_ref_func_t *release)
130{
131 if (!release)
132 release = percpu_ref_exit;
133 return percpu_ref_init(cnt, release, /*percpu mode*/0, GFP_NOFS);
134}
135
136static inline void au_lcnt_wait_for_fin(au_lcnt_t *cnt __maybe_unused)
137{
138 synchronize_rcu();
139}
140
141static inline void au_lcnt_fin(au_lcnt_t *cnt, int do_sync)
142{
143 percpu_ref_kill(cnt);
144 if (do_sync)
145 au_lcnt_wait_for_fin(cnt);
146}
147
148static inline void au_lcnt_inc(au_lcnt_t *cnt)
149{
150 percpu_ref_get(cnt);
151}
152
153static inline void au_lcnt_dec(au_lcnt_t *cnt)
154{
155 percpu_ref_put(cnt);
156}
157
158/*
159 * avoid calling this func as possible.
160 */
161static inline long au_lcnt_read(au_lcnt_t *cnt, int do_rev)
162{
163 long l;
164
165 percpu_ref_switch_to_atomic_sync(cnt);
166 l = atomic_long_read(&cnt->count);
167 if (do_rev)
168 percpu_ref_switch_to_percpu(cnt);
169
170 /* percpu_ref is initialized by 1 instead of 0 */
171 return l - 1;
172}
173#endif
174
175#ifdef CONFIG_AUFS_DEBUG
176#define AuLCntZero(val) do { \
177 long l = val; \
178 if (l) \
179 AuDbg("%s = %ld\n", #val, l); \
180} while (0)
181#else
182#define AuLCntZero(val) do {} while (0)
183#endif
184
185#endif /* __KERNEL__ */
186#endif /* __AUFS_LCNT_H__ */