]>
Commit | Line | Data |
---|---|---|
e14748e8 SF |
1 | /* |
2 | * Copyright (C) 2005-2016 Junjiro R. Okajima | |
3 | * | |
4 | * This program, aufs is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License as published by | |
6 | * the Free Software Foundation; either version 2 of the License, or | |
7 | * (at your option) any later version. | |
8 | * | |
9 | * This program is distributed in the hope that it will be useful, | |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | * GNU General Public License for more details. | |
13 | * | |
14 | * You should have received a copy of the GNU General Public License | |
15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
16 | */ | |
17 | ||
18 | /* | |
19 | * file operations | |
20 | */ | |
21 | ||
22 | #ifndef __AUFS_FILE_H__ | |
23 | #define __AUFS_FILE_H__ | |
24 | ||
25 | #ifdef __KERNEL__ | |
26 | ||
27 | #include <linux/file.h> | |
28 | #include <linux/fs.h> | |
29 | #include <linux/poll.h> | |
30 | #include "rwsem.h" | |
31 | ||
32 | struct au_branch; | |
33 | struct au_hfile { | |
34 | struct file *hf_file; | |
35 | struct au_branch *hf_br; | |
36 | }; | |
37 | ||
38 | struct au_vdir; | |
39 | struct au_fidir { | |
40 | aufs_bindex_t fd_bbot; | |
41 | aufs_bindex_t fd_nent; | |
42 | struct au_vdir *fd_vdir_cache; | |
43 | struct au_hfile fd_hfile[]; | |
44 | }; | |
45 | ||
46 | static inline int au_fidir_sz(int nent) | |
47 | { | |
48 | AuDebugOn(nent < 0); | |
49 | return sizeof(struct au_fidir) + sizeof(struct au_hfile) * nent; | |
50 | } | |
51 | ||
52 | struct au_finfo { | |
53 | atomic_t fi_generation; | |
54 | ||
55 | struct au_rwsem fi_rwsem; | |
56 | aufs_bindex_t fi_btop; | |
57 | ||
58 | /* do not union them */ | |
59 | struct { /* for non-dir */ | |
60 | struct au_hfile fi_htop; | |
61 | atomic_t fi_mmapped; | |
62 | }; | |
63 | struct au_fidir *fi_hdir; /* for dir only */ | |
64 | ||
65 | struct hlist_node fi_hlist; | |
66 | union { | |
67 | struct file *fi_file; /* very ugly */ | |
68 | struct llist_node fi_lnode; /* delayed free */ | |
69 | }; | |
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 no_lock; | |
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); | |
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 | unsigned int aufs_poll(struct file *file, poll_table *wait); | |
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); | |
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, int atonce); | |
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 | /* | |
151 | * fi_read_lock, fi_write_lock, | |
152 | * fi_read_unlock, fi_write_unlock, fi_downgrade_lock | |
153 | */ | |
154 | AuSimpleRwsemFuncs(fi, struct file *f, &au_fi(f)->fi_rwsem); | |
155 | ||
156 | #define FiMustNoWaiters(f) AuRwMustNoWaiters(&au_fi(f)->fi_rwsem) | |
157 | #define FiMustAnyLock(f) AuRwMustAnyLock(&au_fi(f)->fi_rwsem) | |
158 | #define FiMustWriteLock(f) AuRwMustWriteLock(&au_fi(f)->fi_rwsem) | |
159 | ||
160 | /* ---------------------------------------------------------------------- */ | |
161 | ||
162 | /* todo: hard/soft set? */ | |
163 | static inline aufs_bindex_t au_fbtop(struct file *file) | |
164 | { | |
165 | FiMustAnyLock(file); | |
166 | return au_fi(file)->fi_btop; | |
167 | } | |
168 | ||
169 | static inline aufs_bindex_t au_fbbot_dir(struct file *file) | |
170 | { | |
171 | FiMustAnyLock(file); | |
172 | AuDebugOn(!au_fi(file)->fi_hdir); | |
173 | return au_fi(file)->fi_hdir->fd_bbot; | |
174 | } | |
175 | ||
176 | static inline struct au_vdir *au_fvdir_cache(struct file *file) | |
177 | { | |
178 | FiMustAnyLock(file); | |
179 | AuDebugOn(!au_fi(file)->fi_hdir); | |
180 | return au_fi(file)->fi_hdir->fd_vdir_cache; | |
181 | } | |
182 | ||
183 | static inline void au_set_fbtop(struct file *file, aufs_bindex_t bindex) | |
184 | { | |
185 | FiMustWriteLock(file); | |
186 | au_fi(file)->fi_btop = bindex; | |
187 | } | |
188 | ||
189 | static inline void au_set_fbbot_dir(struct file *file, aufs_bindex_t bindex) | |
190 | { | |
191 | FiMustWriteLock(file); | |
192 | AuDebugOn(!au_fi(file)->fi_hdir); | |
193 | au_fi(file)->fi_hdir->fd_bbot = bindex; | |
194 | } | |
195 | ||
196 | static inline void au_set_fvdir_cache(struct file *file, | |
197 | struct au_vdir *vdir_cache) | |
198 | { | |
199 | FiMustWriteLock(file); | |
200 | AuDebugOn(!au_fi(file)->fi_hdir); | |
201 | au_fi(file)->fi_hdir->fd_vdir_cache = vdir_cache; | |
202 | } | |
203 | ||
204 | static inline struct file *au_hf_top(struct file *file) | |
205 | { | |
206 | FiMustAnyLock(file); | |
207 | AuDebugOn(au_fi(file)->fi_hdir); | |
208 | return au_fi(file)->fi_htop.hf_file; | |
209 | } | |
210 | ||
211 | static inline struct file *au_hf_dir(struct file *file, aufs_bindex_t bindex) | |
212 | { | |
213 | FiMustAnyLock(file); | |
214 | AuDebugOn(!au_fi(file)->fi_hdir); | |
215 | return au_fi(file)->fi_hdir->fd_hfile[0 + bindex].hf_file; | |
216 | } | |
217 | ||
218 | /* todo: memory barrier? */ | |
219 | static inline unsigned int au_figen(struct file *f) | |
220 | { | |
221 | return atomic_read(&au_fi(f)->fi_generation); | |
222 | } | |
223 | ||
224 | static inline void au_set_mmapped(struct file *f) | |
225 | { | |
226 | if (atomic_inc_return(&au_fi(f)->fi_mmapped)) | |
227 | return; | |
228 | pr_warn("fi_mmapped wrapped around\n"); | |
229 | while (!atomic_inc_return(&au_fi(f)->fi_mmapped)) | |
230 | ; | |
231 | } | |
232 | ||
233 | static inline void au_unset_mmapped(struct file *f) | |
234 | { | |
235 | atomic_dec(&au_fi(f)->fi_mmapped); | |
236 | } | |
237 | ||
238 | static inline int au_test_mmapped(struct file *f) | |
239 | { | |
240 | return atomic_read(&au_fi(f)->fi_mmapped); | |
241 | } | |
242 | ||
243 | /* customize vma->vm_file */ | |
244 | ||
245 | static inline void au_do_vm_file_reset(struct vm_area_struct *vma, | |
246 | struct file *file) | |
247 | { | |
248 | struct file *f; | |
249 | ||
250 | f = vma->vm_file; | |
251 | get_file(file); | |
252 | vma->vm_file = file; | |
253 | fput(f); | |
254 | } | |
255 | ||
256 | #ifdef CONFIG_MMU | |
257 | #define AuDbgVmRegion(file, vma) do {} while (0) | |
258 | ||
259 | static inline void au_vm_file_reset(struct vm_area_struct *vma, | |
260 | struct file *file) | |
261 | { | |
262 | au_do_vm_file_reset(vma, file); | |
263 | } | |
264 | #else | |
265 | #define AuDbgVmRegion(file, vma) \ | |
266 | AuDebugOn((vma)->vm_region && (vma)->vm_region->vm_file != (file)) | |
267 | ||
268 | static inline void au_vm_file_reset(struct vm_area_struct *vma, | |
269 | struct file *file) | |
270 | { | |
271 | struct file *f; | |
272 | ||
273 | au_do_vm_file_reset(vma, file); | |
274 | f = vma->vm_region->vm_file; | |
275 | get_file(file); | |
276 | vma->vm_region->vm_file = file; | |
277 | fput(f); | |
278 | } | |
279 | #endif /* CONFIG_MMU */ | |
280 | ||
281 | /* handle vma->vm_prfile */ | |
282 | static inline void au_vm_prfile_set(struct vm_area_struct *vma, | |
283 | struct file *file) | |
284 | { | |
285 | get_file(file); | |
286 | vma->vm_prfile = file; | |
287 | #ifndef CONFIG_MMU | |
288 | get_file(file); | |
289 | vma->vm_region->vm_prfile = file; | |
290 | #endif | |
291 | } | |
292 | ||
293 | #endif /* __KERNEL__ */ | |
294 | #endif /* __AUFS_FILE_H__ */ |