]>
Commit | Line | Data |
---|---|---|
7fea21ae AR |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Copyright (C) 2005-2021 Junjiro R. Okajima | |
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 | * superblock private data | |
21 | */ | |
22 | ||
23 | #include <linux/iversion.h> | |
24 | #include "aufs.h" | |
25 | ||
26 | /* | |
27 | * they are necessary regardless sysfs is disabled. | |
28 | */ | |
29 | void au_si_free(struct kobject *kobj) | |
30 | { | |
31 | int i; | |
32 | struct au_sbinfo *sbinfo; | |
33 | char *locked __maybe_unused; /* debug only */ | |
34 | ||
35 | sbinfo = container_of(kobj, struct au_sbinfo, si_kobj); | |
36 | for (i = 0; i < AuPlink_NHASH; i++) | |
37 | AuDebugOn(!hlist_bl_empty(sbinfo->si_plink + i)); | |
38 | AuDebugOn(atomic_read(&sbinfo->si_nowait.nw_len)); | |
39 | ||
40 | AuLCntZero(au_lcnt_read(&sbinfo->si_ninodes, /*do_rev*/0)); | |
41 | au_lcnt_fin(&sbinfo->si_ninodes, /*do_sync*/0); | |
42 | AuLCntZero(au_lcnt_read(&sbinfo->si_nfiles, /*do_rev*/0)); | |
43 | au_lcnt_fin(&sbinfo->si_nfiles, /*do_sync*/0); | |
44 | ||
45 | dbgaufs_si_fin(sbinfo); | |
46 | au_rw_write_lock(&sbinfo->si_rwsem); | |
47 | au_br_free(sbinfo); | |
48 | au_rw_write_unlock(&sbinfo->si_rwsem); | |
49 | ||
50 | au_kfree_try_rcu(sbinfo->si_branch); | |
51 | mutex_destroy(&sbinfo->si_xib_mtx); | |
52 | AuRwDestroy(&sbinfo->si_rwsem); | |
53 | ||
54 | au_lcnt_wait_for_fin(&sbinfo->si_ninodes); | |
55 | /* si_nfiles is waited too */ | |
56 | au_kfree_rcu(sbinfo); | |
57 | } | |
58 | ||
59 | int au_si_alloc(struct super_block *sb) | |
60 | { | |
61 | int err, i; | |
62 | struct au_sbinfo *sbinfo; | |
63 | ||
64 | err = -ENOMEM; | |
65 | sbinfo = kzalloc(sizeof(*sbinfo), GFP_NOFS); | |
66 | if (unlikely(!sbinfo)) | |
67 | goto out; | |
68 | ||
69 | /* will be reallocated separately */ | |
70 | sbinfo->si_branch = kzalloc(sizeof(*sbinfo->si_branch), GFP_NOFS); | |
71 | if (unlikely(!sbinfo->si_branch)) | |
72 | goto out_sbinfo; | |
73 | ||
74 | err = sysaufs_si_init(sbinfo); | |
75 | if (!err) { | |
76 | dbgaufs_si_null(sbinfo); | |
77 | err = dbgaufs_si_init(sbinfo); | |
78 | if (unlikely(err)) | |
79 | kobject_put(&sbinfo->si_kobj); | |
80 | } | |
81 | if (unlikely(err)) | |
82 | goto out_br; | |
83 | ||
84 | au_nwt_init(&sbinfo->si_nowait); | |
85 | au_rw_init_wlock(&sbinfo->si_rwsem); | |
86 | ||
87 | au_lcnt_init(&sbinfo->si_ninodes, /*release*/NULL); | |
88 | au_lcnt_init(&sbinfo->si_nfiles, /*release*/NULL); | |
89 | ||
90 | sbinfo->si_bbot = -1; | |
91 | sbinfo->si_last_br_id = AUFS_BRANCH_MAX / 2; | |
92 | ||
93 | sbinfo->si_wbr_copyup = AuWbrCopyup_Def; | |
94 | sbinfo->si_wbr_create = AuWbrCreate_Def; | |
95 | sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + sbinfo->si_wbr_copyup; | |
96 | sbinfo->si_wbr_create_ops = au_wbr_create_ops + sbinfo->si_wbr_create; | |
97 | ||
98 | au_fhsm_init(sbinfo); | |
99 | ||
100 | sbinfo->si_mntflags = au_opts_plink(AuOpt_Def); | |
101 | ||
102 | sbinfo->si_xino_jiffy = jiffies; | |
103 | sbinfo->si_xino_expire | |
104 | = msecs_to_jiffies(AUFS_XINO_DEF_SEC * MSEC_PER_SEC); | |
105 | mutex_init(&sbinfo->si_xib_mtx); | |
106 | /* leave si_xib_last_pindex and si_xib_next_bit */ | |
107 | ||
108 | INIT_HLIST_BL_HEAD(&sbinfo->si_aopen); | |
109 | ||
110 | sbinfo->si_rdcache = msecs_to_jiffies(AUFS_RDCACHE_DEF * MSEC_PER_SEC); | |
111 | sbinfo->si_rdblk = AUFS_RDBLK_DEF; | |
112 | sbinfo->si_rdhash = AUFS_RDHASH_DEF; | |
113 | sbinfo->si_dirwh = AUFS_DIRWH_DEF; | |
114 | ||
115 | for (i = 0; i < AuPlink_NHASH; i++) | |
116 | INIT_HLIST_BL_HEAD(sbinfo->si_plink + i); | |
117 | init_waitqueue_head(&sbinfo->si_plink_wq); | |
118 | spin_lock_init(&sbinfo->si_plink_maint_lock); | |
119 | ||
120 | INIT_HLIST_BL_HEAD(&sbinfo->si_files); | |
121 | ||
122 | /* with getattr by default */ | |
123 | sbinfo->si_iop_array = aufs_iop; | |
124 | ||
125 | /* leave other members for sysaufs and si_mnt. */ | |
126 | sbinfo->si_sb = sb; | |
127 | sb->s_fs_info = sbinfo; | |
128 | si_pid_set(sb); | |
129 | return 0; /* success */ | |
130 | ||
131 | out_br: | |
132 | au_kfree_try_rcu(sbinfo->si_branch); | |
133 | out_sbinfo: | |
134 | au_kfree_rcu(sbinfo); | |
135 | out: | |
136 | return err; | |
137 | } | |
138 | ||
139 | int au_sbr_realloc(struct au_sbinfo *sbinfo, int nbr, int may_shrink) | |
140 | { | |
141 | int err, sz; | |
142 | struct au_branch **brp; | |
143 | ||
144 | AuRwMustWriteLock(&sbinfo->si_rwsem); | |
145 | ||
146 | err = -ENOMEM; | |
147 | sz = sizeof(*brp) * (sbinfo->si_bbot + 1); | |
148 | if (unlikely(!sz)) | |
149 | sz = sizeof(*brp); | |
150 | brp = au_kzrealloc(sbinfo->si_branch, sz, sizeof(*brp) * nbr, GFP_NOFS, | |
151 | may_shrink); | |
152 | if (brp) { | |
153 | sbinfo->si_branch = brp; | |
154 | err = 0; | |
155 | } | |
156 | ||
157 | return err; | |
158 | } | |
159 | ||
160 | /* ---------------------------------------------------------------------- */ | |
161 | ||
162 | unsigned int au_sigen_inc(struct super_block *sb) | |
163 | { | |
164 | unsigned int gen; | |
165 | struct inode *inode; | |
166 | ||
167 | SiMustWriteLock(sb); | |
168 | ||
169 | gen = ++au_sbi(sb)->si_generation; | |
170 | au_update_digen(sb->s_root); | |
171 | inode = d_inode(sb->s_root); | |
172 | au_update_iigen(inode, /*half*/0); | |
173 | inode_inc_iversion(inode); | |
174 | return gen; | |
175 | } | |
176 | ||
177 | aufs_bindex_t au_new_br_id(struct super_block *sb) | |
178 | { | |
179 | aufs_bindex_t br_id; | |
180 | int i; | |
181 | struct au_sbinfo *sbinfo; | |
182 | ||
183 | SiMustWriteLock(sb); | |
184 | ||
185 | sbinfo = au_sbi(sb); | |
186 | for (i = 0; i <= AUFS_BRANCH_MAX; i++) { | |
187 | br_id = ++sbinfo->si_last_br_id; | |
188 | AuDebugOn(br_id < 0); | |
189 | if (br_id && au_br_index(sb, br_id) < 0) | |
190 | return br_id; | |
191 | } | |
192 | ||
193 | return -1; | |
194 | } | |
195 | ||
196 | /* ---------------------------------------------------------------------- */ | |
197 | ||
198 | /* it is ok that new 'nwt' tasks are appended while we are sleeping */ | |
199 | int si_read_lock(struct super_block *sb, int flags) | |
200 | { | |
201 | int err; | |
202 | ||
203 | err = 0; | |
204 | if (au_ftest_lock(flags, FLUSH)) | |
205 | au_nwt_flush(&au_sbi(sb)->si_nowait); | |
206 | ||
207 | si_noflush_read_lock(sb); | |
208 | err = au_plink_maint(sb, flags); | |
209 | if (unlikely(err)) | |
210 | si_read_unlock(sb); | |
211 | ||
212 | return err; | |
213 | } | |
214 | ||
215 | int si_write_lock(struct super_block *sb, int flags) | |
216 | { | |
217 | int err; | |
218 | ||
219 | if (au_ftest_lock(flags, FLUSH)) | |
220 | au_nwt_flush(&au_sbi(sb)->si_nowait); | |
221 | ||
222 | si_noflush_write_lock(sb); | |
223 | err = au_plink_maint(sb, flags); | |
224 | if (unlikely(err)) | |
225 | si_write_unlock(sb); | |
226 | ||
227 | return err; | |
228 | } | |
229 | ||
230 | /* dentry and super_block lock. call at entry point */ | |
231 | int aufs_read_lock(struct dentry *dentry, int flags) | |
232 | { | |
233 | int err; | |
234 | struct super_block *sb; | |
235 | ||
236 | sb = dentry->d_sb; | |
237 | err = si_read_lock(sb, flags); | |
238 | if (unlikely(err)) | |
239 | goto out; | |
240 | ||
241 | if (au_ftest_lock(flags, DW)) | |
242 | di_write_lock_child(dentry); | |
243 | else | |
244 | di_read_lock_child(dentry, flags); | |
245 | ||
246 | if (au_ftest_lock(flags, GEN)) { | |
247 | err = au_digen_test(dentry, au_sigen(sb)); | |
248 | if (!au_opt_test(au_mntflags(sb), UDBA_NONE)) | |
249 | AuDebugOn(!err && au_dbrange_test(dentry)); | |
250 | else if (!err) | |
251 | err = au_dbrange_test(dentry); | |
252 | if (unlikely(err)) | |
253 | aufs_read_unlock(dentry, flags); | |
254 | } | |
255 | ||
256 | out: | |
257 | return err; | |
258 | } | |
259 | ||
260 | void aufs_read_unlock(struct dentry *dentry, int flags) | |
261 | { | |
262 | if (au_ftest_lock(flags, DW)) | |
263 | di_write_unlock(dentry); | |
264 | else | |
265 | di_read_unlock(dentry, flags); | |
266 | si_read_unlock(dentry->d_sb); | |
267 | } | |
268 | ||
269 | void aufs_write_lock(struct dentry *dentry) | |
270 | { | |
271 | si_write_lock(dentry->d_sb, AuLock_FLUSH | AuLock_NOPLMW); | |
272 | di_write_lock_child(dentry); | |
273 | } | |
274 | ||
275 | void aufs_write_unlock(struct dentry *dentry) | |
276 | { | |
277 | di_write_unlock(dentry); | |
278 | si_write_unlock(dentry->d_sb); | |
279 | } | |
280 | ||
281 | int aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int flags) | |
282 | { | |
283 | int err; | |
284 | unsigned int sigen; | |
285 | struct super_block *sb; | |
286 | ||
287 | sb = d1->d_sb; | |
288 | err = si_read_lock(sb, flags); | |
289 | if (unlikely(err)) | |
290 | goto out; | |
291 | ||
292 | di_write_lock2_child(d1, d2, au_ftest_lock(flags, DIRS)); | |
293 | ||
294 | if (au_ftest_lock(flags, GEN)) { | |
295 | sigen = au_sigen(sb); | |
296 | err = au_digen_test(d1, sigen); | |
297 | AuDebugOn(!err && au_dbrange_test(d1)); | |
298 | if (!err) { | |
299 | err = au_digen_test(d2, sigen); | |
300 | AuDebugOn(!err && au_dbrange_test(d2)); | |
301 | } | |
302 | if (unlikely(err)) | |
303 | aufs_read_and_write_unlock2(d1, d2); | |
304 | } | |
305 | ||
306 | out: | |
307 | return err; | |
308 | } | |
309 | ||
310 | void aufs_read_and_write_unlock2(struct dentry *d1, struct dentry *d2) | |
311 | { | |
312 | di_write_unlock2(d1, d2); | |
313 | si_read_unlock(d1->d_sb); | |
314 | } |