]>
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 | * file operations | |
21 | */ | |
22 | ||
23 | #ifndef __AUFS_FILE_H__ | |
24 | #define __AUFS_FILE_H__ | |
25 | ||
26 | #ifdef __KERNEL__ | |
27 | ||
28 | #include <linux/file.h> | |
29 | #include <linux/fs.h> | |
30 | #include <linux/mm_types.h> | |
31 | #include <linux/poll.h> | |
32 | #include "rwsem.h" | |
33 | ||
34 | struct au_branch; | |
35 | struct au_hfile { | |
36 | struct file *hf_file; | |
37 | struct au_branch *hf_br; | |
38 | }; | |
39 | ||
40 | struct au_vdir; | |
41 | struct au_fidir { | |
42 | aufs_bindex_t fd_bbot; | |
43 | aufs_bindex_t fd_nent; | |
44 | struct au_vdir *fd_vdir_cache; | |
45 | struct au_hfile fd_hfile[]; | |
46 | }; | |
47 | ||
48 | static inline int au_fidir_sz(int nent) | |
49 | { | |
50 | AuDebugOn(nent < 0); | |
51 | return sizeof(struct au_fidir) + sizeof(struct au_hfile) * nent; | |
52 | } | |
53 | ||
54 | struct au_finfo { | |
55 | atomic_t fi_generation; | |
56 | ||
57 | struct au_rwsem fi_rwsem; | |
58 | aufs_bindex_t fi_btop; | |
59 | ||
60 | /* do not union them */ | |
61 | struct { /* for non-dir */ | |
62 | struct au_hfile fi_htop; | |
63 | atomic_t fi_mmapped; | |
64 | }; | |
65 | struct au_fidir *fi_hdir; /* for dir only */ | |
66 | ||
67 | struct hlist_bl_node fi_hlist; | |
68 | struct file *fi_file; /* very ugly */ | |
69 | struct rcu_head rcu; | |
70 | } ____cacheline_aligned_in_smp; | |
71 | ||
72 | /* ---------------------------------------------------------------------- */ | |
73 | ||
74 | /* file.c */ | |
75 | extern const struct address_space_operations aufs_aop; | |
76 | unsigned int au_file_roflags(unsigned int flags); | |
77 | struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags, | |
78 | struct file *file, int force_wr); | |
79 | struct au_do_open_args { | |
80 | int aopen; | |
81 | int (*open)(struct file *file, int flags, | |
82 | struct file *h_file); | |
83 | struct au_fidir *fidir; | |
84 | struct file *h_file; | |
85 | }; | |
86 | int au_do_open(struct file *file, struct au_do_open_args *args); | |
87 | int au_reopen_nondir(struct file *file); | |
88 | struct au_pin; | |
89 | int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin); | |
90 | int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file), | |
91 | int wlock, unsigned int fi_lsc); | |
92 | int au_do_flush(struct file *file, fl_owner_t id, | |
93 | int (*flush)(struct file *file, fl_owner_t id)); | |
94 | ||
95 | /* poll.c */ | |
96 | #ifdef CONFIG_AUFS_POLL | |
97 | __poll_t aufs_poll(struct file *file, struct poll_table_struct *pt); | |
98 | #endif | |
99 | ||
100 | #ifdef CONFIG_AUFS_BR_HFSPLUS | |
101 | /* hfsplus.c */ | |
102 | struct file *au_h_open_pre(struct dentry *dentry, aufs_bindex_t bindex, | |
103 | int force_wr); | |
104 | void au_h_open_post(struct dentry *dentry, aufs_bindex_t bindex, | |
105 | struct file *h_file); | |
106 | #else | |
107 | AuStub(struct file *, au_h_open_pre, return NULL, struct dentry *dentry, | |
108 | aufs_bindex_t bindex, int force_wr) | |
109 | AuStubVoid(au_h_open_post, struct dentry *dentry, aufs_bindex_t bindex, | |
110 | struct file *h_file); | |
111 | #endif | |
112 | ||
113 | /* f_op.c */ | |
114 | extern const struct file_operations aufs_file_fop; | |
115 | int au_do_open_nondir(struct file *file, int flags, struct file *h_file); | |
116 | int aufs_release_nondir(struct inode *inode __maybe_unused, struct file *file); | |
117 | struct file *au_read_pre(struct file *file, int keep_fi, unsigned int lsc); | |
118 | ||
119 | /* finfo.c */ | |
120 | void au_hfput(struct au_hfile *hf, int execed); | |
121 | void au_set_h_fptr(struct file *file, aufs_bindex_t bindex, | |
122 | struct file *h_file); | |
123 | ||
124 | void au_update_figen(struct file *file); | |
125 | struct au_fidir *au_fidir_alloc(struct super_block *sb); | |
126 | int au_fidir_realloc(struct au_finfo *finfo, int nbr, int may_shrink); | |
127 | ||
128 | void au_fi_init_once(void *_fi); | |
129 | void au_finfo_fin(struct file *file); | |
130 | int au_finfo_init(struct file *file, struct au_fidir *fidir); | |
131 | ||
132 | /* ioctl.c */ | |
133 | long aufs_ioctl_nondir(struct file *file, unsigned int cmd, unsigned long arg); | |
134 | #ifdef CONFIG_COMPAT | |
135 | long aufs_compat_ioctl_dir(struct file *file, unsigned int cmd, | |
136 | unsigned long arg); | |
137 | long aufs_compat_ioctl_nondir(struct file *file, unsigned int cmd, | |
138 | unsigned long arg); | |
139 | #endif | |
140 | ||
141 | /* ---------------------------------------------------------------------- */ | |
142 | ||
143 | static inline struct au_finfo *au_fi(struct file *file) | |
144 | { | |
145 | return file->private_data; | |
146 | } | |
147 | ||
148 | /* ---------------------------------------------------------------------- */ | |
149 | ||
150 | #define fi_read_lock(f) au_rw_read_lock(&au_fi(f)->fi_rwsem) | |
151 | #define fi_write_lock(f) au_rw_write_lock(&au_fi(f)->fi_rwsem) | |
152 | #define fi_read_trylock(f) au_rw_read_trylock(&au_fi(f)->fi_rwsem) | |
153 | #define fi_write_trylock(f) au_rw_write_trylock(&au_fi(f)->fi_rwsem) | |
154 | /* | |
155 | #define fi_read_trylock_nested(f) \ | |
156 | au_rw_read_trylock_nested(&au_fi(f)->fi_rwsem) | |
157 | #define fi_write_trylock_nested(f) \ | |
158 | au_rw_write_trylock_nested(&au_fi(f)->fi_rwsem) | |
159 | */ | |
160 | ||
161 | #define fi_read_unlock(f) au_rw_read_unlock(&au_fi(f)->fi_rwsem) | |
162 | #define fi_write_unlock(f) au_rw_write_unlock(&au_fi(f)->fi_rwsem) | |
163 | #define fi_downgrade_lock(f) au_rw_dgrade_lock(&au_fi(f)->fi_rwsem) | |
164 | ||
165 | /* lock subclass for finfo */ | |
166 | enum { | |
167 | AuLsc_FI_1, | |
168 | AuLsc_FI_2 | |
169 | }; | |
170 | ||
171 | static inline void fi_read_lock_nested(struct file *f, unsigned int lsc) | |
172 | { | |
173 | au_rw_read_lock_nested(&au_fi(f)->fi_rwsem, lsc); | |
174 | } | |
175 | ||
176 | static inline void fi_write_lock_nested(struct file *f, unsigned int lsc) | |
177 | { | |
178 | au_rw_write_lock_nested(&au_fi(f)->fi_rwsem, lsc); | |
179 | } | |
180 | ||
181 | /* | |
182 | * fi_read_lock_1, fi_write_lock_1, | |
183 | * fi_read_lock_2, fi_write_lock_2 | |
184 | */ | |
185 | #define AuReadLockFunc(name) \ | |
186 | static inline void fi_read_lock_##name(struct file *f) \ | |
187 | { fi_read_lock_nested(f, AuLsc_FI_##name); } | |
188 | ||
189 | #define AuWriteLockFunc(name) \ | |
190 | static inline void fi_write_lock_##name(struct file *f) \ | |
191 | { fi_write_lock_nested(f, AuLsc_FI_##name); } | |
192 | ||
193 | #define AuRWLockFuncs(name) \ | |
194 | AuReadLockFunc(name) \ | |
195 | AuWriteLockFunc(name) | |
196 | ||
197 | AuRWLockFuncs(1); | |
198 | AuRWLockFuncs(2); | |
199 | ||
200 | #undef AuReadLockFunc | |
201 | #undef AuWriteLockFunc | |
202 | #undef AuRWLockFuncs | |
203 | ||
204 | #define FiMustNoWaiters(f) AuRwMustNoWaiters(&au_fi(f)->fi_rwsem) | |
205 | #define FiMustAnyLock(f) AuRwMustAnyLock(&au_fi(f)->fi_rwsem) | |
206 | #define FiMustWriteLock(f) AuRwMustWriteLock(&au_fi(f)->fi_rwsem) | |
207 | ||
208 | /* ---------------------------------------------------------------------- */ | |
209 | ||
210 | /* todo: hard/soft set? */ | |
211 | static inline aufs_bindex_t au_fbtop(struct file *file) | |
212 | { | |
213 | FiMustAnyLock(file); | |
214 | return au_fi(file)->fi_btop; | |
215 | } | |
216 | ||
217 | static inline aufs_bindex_t au_fbbot_dir(struct file *file) | |
218 | { | |
219 | FiMustAnyLock(file); | |
220 | AuDebugOn(!au_fi(file)->fi_hdir); | |
221 | return au_fi(file)->fi_hdir->fd_bbot; | |
222 | } | |
223 | ||
224 | static inline struct au_vdir *au_fvdir_cache(struct file *file) | |
225 | { | |
226 | FiMustAnyLock(file); | |
227 | AuDebugOn(!au_fi(file)->fi_hdir); | |
228 | return au_fi(file)->fi_hdir->fd_vdir_cache; | |
229 | } | |
230 | ||
231 | static inline void au_set_fbtop(struct file *file, aufs_bindex_t bindex) | |
232 | { | |
233 | FiMustWriteLock(file); | |
234 | au_fi(file)->fi_btop = bindex; | |
235 | } | |
236 | ||
237 | static inline void au_set_fbbot_dir(struct file *file, aufs_bindex_t bindex) | |
238 | { | |
239 | FiMustWriteLock(file); | |
240 | AuDebugOn(!au_fi(file)->fi_hdir); | |
241 | au_fi(file)->fi_hdir->fd_bbot = bindex; | |
242 | } | |
243 | ||
244 | static inline void au_set_fvdir_cache(struct file *file, | |
245 | struct au_vdir *vdir_cache) | |
246 | { | |
247 | FiMustWriteLock(file); | |
248 | AuDebugOn(!au_fi(file)->fi_hdir); | |
249 | au_fi(file)->fi_hdir->fd_vdir_cache = vdir_cache; | |
250 | } | |
251 | ||
252 | static inline struct file *au_hf_top(struct file *file) | |
253 | { | |
254 | FiMustAnyLock(file); | |
255 | AuDebugOn(au_fi(file)->fi_hdir); | |
256 | return au_fi(file)->fi_htop.hf_file; | |
257 | } | |
258 | ||
259 | static inline struct file *au_hf_dir(struct file *file, aufs_bindex_t bindex) | |
260 | { | |
261 | FiMustAnyLock(file); | |
262 | AuDebugOn(!au_fi(file)->fi_hdir); | |
263 | return au_fi(file)->fi_hdir->fd_hfile[0 + bindex].hf_file; | |
264 | } | |
265 | ||
266 | /* todo: memory barrier? */ | |
267 | static inline unsigned int au_figen(struct file *f) | |
268 | { | |
269 | return atomic_read(&au_fi(f)->fi_generation); | |
270 | } | |
271 | ||
272 | static inline void au_set_mmapped(struct file *f) | |
273 | { | |
274 | if (atomic_inc_return(&au_fi(f)->fi_mmapped)) | |
275 | return; | |
276 | pr_warn("fi_mmapped wrapped around\n"); | |
277 | while (!atomic_inc_return(&au_fi(f)->fi_mmapped)) | |
278 | ; | |
279 | } | |
280 | ||
281 | static inline void au_unset_mmapped(struct file *f) | |
282 | { | |
283 | atomic_dec(&au_fi(f)->fi_mmapped); | |
284 | } | |
285 | ||
286 | static inline int au_test_mmapped(struct file *f) | |
287 | { | |
288 | return atomic_read(&au_fi(f)->fi_mmapped); | |
289 | } | |
290 | ||
291 | /* customize vma->vm_file */ | |
292 | ||
293 | static inline void au_do_vm_file_reset(struct vm_area_struct *vma, | |
294 | struct file *file) | |
295 | { | |
296 | struct file *f; | |
297 | ||
298 | f = vma->vm_file; | |
299 | get_file(file); | |
300 | vma->vm_file = file; | |
301 | fput(f); | |
302 | } | |
303 | ||
304 | #ifdef CONFIG_MMU | |
305 | #define AuDbgVmRegion(file, vma) do {} while (0) | |
306 | ||
307 | static inline void au_vm_file_reset(struct vm_area_struct *vma, | |
308 | struct file *file) | |
309 | { | |
310 | au_do_vm_file_reset(vma, file); | |
311 | } | |
312 | #else | |
313 | #define AuDbgVmRegion(file, vma) \ | |
314 | AuDebugOn((vma)->vm_region && (vma)->vm_region->vm_file != (file)) | |
315 | ||
316 | static inline void au_vm_file_reset(struct vm_area_struct *vma, | |
317 | struct file *file) | |
318 | { | |
319 | struct file *f; | |
320 | ||
321 | au_do_vm_file_reset(vma, file); | |
322 | f = vma->vm_region->vm_file; | |
323 | get_file(file); | |
324 | vma->vm_region->vm_file = file; | |
325 | fput(f); | |
326 | } | |
327 | #endif /* CONFIG_MMU */ | |
328 | ||
329 | /* handle vma->vm_prfile */ | |
330 | static inline void au_vm_prfile_set(struct vm_area_struct *vma, | |
331 | struct file *file) | |
332 | { | |
333 | get_file(file); | |
334 | vma->vm_prfile = file; | |
335 | #ifndef CONFIG_MMU | |
336 | get_file(file); | |
337 | vma->vm_region->vm_prfile = file; | |
338 | #endif | |
339 | } | |
340 | ||
341 | #endif /* __KERNEL__ */ | |
342 | #endif /* __AUFS_FILE_H__ */ |