]>
Commit | Line | Data |
---|---|---|
bbb1e54d MS |
1 | /* |
2 | * Copyright (C) 2011 Novell Inc. | |
3 | * Copyright (C) 2016 Red Hat, Inc. | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify it | |
6 | * under the terms of the GNU General Public License version 2 as published by | |
7 | * the Free Software Foundation. | |
8 | */ | |
9 | ||
10 | #include <linux/fs.h> | |
11 | #include <linux/mount.h> | |
12 | #include <linux/slab.h> | |
5b825c3a | 13 | #include <linux/cred.h> |
bbb1e54d MS |
14 | #include <linux/xattr.h> |
15 | #include "overlayfs.h" | |
16 | #include "ovl_entry.h" | |
17 | ||
18 | int ovl_want_write(struct dentry *dentry) | |
19 | { | |
20 | struct ovl_fs *ofs = dentry->d_sb->s_fs_info; | |
21 | return mnt_want_write(ofs->upper_mnt); | |
22 | } | |
23 | ||
24 | void ovl_drop_write(struct dentry *dentry) | |
25 | { | |
26 | struct ovl_fs *ofs = dentry->d_sb->s_fs_info; | |
27 | mnt_drop_write(ofs->upper_mnt); | |
28 | } | |
29 | ||
30 | struct dentry *ovl_workdir(struct dentry *dentry) | |
31 | { | |
32 | struct ovl_fs *ofs = dentry->d_sb->s_fs_info; | |
33 | return ofs->workdir; | |
34 | } | |
35 | ||
36 | const struct cred *ovl_override_creds(struct super_block *sb) | |
37 | { | |
38 | struct ovl_fs *ofs = sb->s_fs_info; | |
39 | ||
40 | return override_creds(ofs->creator_cred); | |
41 | } | |
42 | ||
7bcd74b9 AG |
43 | struct super_block *ovl_same_sb(struct super_block *sb) |
44 | { | |
45 | struct ovl_fs *ofs = sb->s_fs_info; | |
46 | ||
47 | return ofs->same_sb; | |
48 | } | |
49 | ||
bbb1e54d MS |
50 | struct ovl_entry *ovl_alloc_entry(unsigned int numlower) |
51 | { | |
52 | size_t size = offsetof(struct ovl_entry, lowerstack[numlower]); | |
53 | struct ovl_entry *oe = kzalloc(size, GFP_KERNEL); | |
54 | ||
55 | if (oe) | |
56 | oe->numlower = numlower; | |
57 | ||
58 | return oe; | |
59 | } | |
60 | ||
61 | bool ovl_dentry_remote(struct dentry *dentry) | |
62 | { | |
63 | return dentry->d_flags & | |
64 | (DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE | | |
65 | DCACHE_OP_REAL); | |
66 | } | |
67 | ||
68 | bool ovl_dentry_weird(struct dentry *dentry) | |
69 | { | |
70 | return dentry->d_flags & (DCACHE_NEED_AUTOMOUNT | | |
71 | DCACHE_MANAGE_TRANSIT | | |
72 | DCACHE_OP_HASH | | |
73 | DCACHE_OP_COMPARE); | |
74 | } | |
75 | ||
76 | enum ovl_path_type ovl_path_type(struct dentry *dentry) | |
77 | { | |
78 | struct ovl_entry *oe = dentry->d_fsdata; | |
79 | enum ovl_path_type type = 0; | |
80 | ||
09d8b586 | 81 | if (ovl_dentry_upper(dentry)) { |
bbb1e54d MS |
82 | type = __OVL_PATH_UPPER; |
83 | ||
84 | /* | |
59548503 | 85 | * Non-dir dentry can hold lower dentry of its copy up origin. |
bbb1e54d | 86 | */ |
59548503 AG |
87 | if (oe->numlower) { |
88 | type |= __OVL_PATH_ORIGIN; | |
89 | if (d_is_dir(dentry)) | |
90 | type |= __OVL_PATH_MERGE; | |
91 | } | |
bbb1e54d MS |
92 | } else { |
93 | if (oe->numlower > 1) | |
94 | type |= __OVL_PATH_MERGE; | |
95 | } | |
96 | return type; | |
97 | } | |
98 | ||
99 | void ovl_path_upper(struct dentry *dentry, struct path *path) | |
100 | { | |
101 | struct ovl_fs *ofs = dentry->d_sb->s_fs_info; | |
bbb1e54d MS |
102 | |
103 | path->mnt = ofs->upper_mnt; | |
09d8b586 | 104 | path->dentry = ovl_dentry_upper(dentry); |
bbb1e54d MS |
105 | } |
106 | ||
107 | void ovl_path_lower(struct dentry *dentry, struct path *path) | |
108 | { | |
109 | struct ovl_entry *oe = dentry->d_fsdata; | |
110 | ||
33006cdf | 111 | *path = oe->numlower ? oe->lowerstack[0] : (struct path) { }; |
bbb1e54d MS |
112 | } |
113 | ||
114 | enum ovl_path_type ovl_path_real(struct dentry *dentry, struct path *path) | |
115 | { | |
116 | enum ovl_path_type type = ovl_path_type(dentry); | |
117 | ||
118 | if (!OVL_TYPE_UPPER(type)) | |
119 | ovl_path_lower(dentry, path); | |
120 | else | |
121 | ovl_path_upper(dentry, path); | |
122 | ||
123 | return type; | |
124 | } | |
125 | ||
126 | struct dentry *ovl_dentry_upper(struct dentry *dentry) | |
127 | { | |
09d8b586 | 128 | return ovl_upperdentry_dereference(OVL_I(d_inode(dentry))); |
bbb1e54d MS |
129 | } |
130 | ||
131 | struct dentry *ovl_dentry_lower(struct dentry *dentry) | |
132 | { | |
133 | struct ovl_entry *oe = dentry->d_fsdata; | |
134 | ||
09d8b586 | 135 | return oe->numlower ? oe->lowerstack[0].dentry : NULL; |
bbb1e54d MS |
136 | } |
137 | ||
138 | struct dentry *ovl_dentry_real(struct dentry *dentry) | |
139 | { | |
09d8b586 | 140 | return ovl_dentry_upper(dentry) ?: ovl_dentry_lower(dentry); |
bbb1e54d MS |
141 | } |
142 | ||
09d8b586 | 143 | struct inode *ovl_inode_upper(struct inode *inode) |
25b7713a | 144 | { |
09d8b586 | 145 | struct dentry *upperdentry = ovl_upperdentry_dereference(OVL_I(inode)); |
25b7713a | 146 | |
09d8b586 MS |
147 | return upperdentry ? d_inode(upperdentry) : NULL; |
148 | } | |
25b7713a | 149 | |
09d8b586 MS |
150 | struct inode *ovl_inode_lower(struct inode *inode) |
151 | { | |
152 | return OVL_I(inode)->lower; | |
153 | } | |
25b7713a | 154 | |
09d8b586 MS |
155 | struct inode *ovl_inode_real(struct inode *inode) |
156 | { | |
157 | return ovl_inode_upper(inode) ?: ovl_inode_lower(inode); | |
25b7713a MS |
158 | } |
159 | ||
09d8b586 | 160 | |
bbb1e54d MS |
161 | struct ovl_dir_cache *ovl_dir_cache(struct dentry *dentry) |
162 | { | |
163 | struct ovl_entry *oe = dentry->d_fsdata; | |
164 | ||
165 | return oe->cache; | |
166 | } | |
167 | ||
168 | void ovl_set_dir_cache(struct dentry *dentry, struct ovl_dir_cache *cache) | |
169 | { | |
170 | struct ovl_entry *oe = dentry->d_fsdata; | |
171 | ||
172 | oe->cache = cache; | |
173 | } | |
174 | ||
175 | bool ovl_dentry_is_opaque(struct dentry *dentry) | |
176 | { | |
177 | struct ovl_entry *oe = dentry->d_fsdata; | |
178 | return oe->opaque; | |
179 | } | |
180 | ||
181 | bool ovl_dentry_is_whiteout(struct dentry *dentry) | |
182 | { | |
183 | return !dentry->d_inode && ovl_dentry_is_opaque(dentry); | |
184 | } | |
185 | ||
5cf5b477 | 186 | void ovl_dentry_set_opaque(struct dentry *dentry) |
bbb1e54d MS |
187 | { |
188 | struct ovl_entry *oe = dentry->d_fsdata; | |
5cf5b477 MS |
189 | |
190 | oe->opaque = true; | |
bbb1e54d MS |
191 | } |
192 | ||
a6c60655 MS |
193 | bool ovl_redirect_dir(struct super_block *sb) |
194 | { | |
195 | struct ovl_fs *ofs = sb->s_fs_info; | |
196 | ||
21a22878 | 197 | return ofs->config.redirect_dir && !ofs->noxattr; |
a6c60655 MS |
198 | } |
199 | ||
200 | const char *ovl_dentry_get_redirect(struct dentry *dentry) | |
201 | { | |
cf31c463 | 202 | return OVL_I(d_inode(dentry))->redirect; |
a6c60655 MS |
203 | } |
204 | ||
205 | void ovl_dentry_set_redirect(struct dentry *dentry, const char *redirect) | |
206 | { | |
cf31c463 | 207 | struct ovl_inode *oi = OVL_I(d_inode(dentry)); |
a6c60655 | 208 | |
cf31c463 MS |
209 | kfree(oi->redirect); |
210 | oi->redirect = redirect; | |
a6c60655 MS |
211 | } |
212 | ||
09d8b586 MS |
213 | void ovl_inode_init(struct inode *inode, struct dentry *upperdentry, |
214 | struct dentry *lowerdentry) | |
bbb1e54d | 215 | { |
09d8b586 MS |
216 | if (upperdentry) |
217 | OVL_I(inode)->__upperdentry = upperdentry; | |
218 | if (lowerdentry) | |
219 | OVL_I(inode)->lower = d_inode(lowerdentry); | |
bbb1e54d | 220 | |
09d8b586 | 221 | ovl_copyattr(d_inode(upperdentry ?: lowerdentry), inode); |
bbb1e54d MS |
222 | } |
223 | ||
09d8b586 | 224 | void ovl_inode_update(struct inode *inode, struct dentry *upperdentry) |
bbb1e54d | 225 | { |
09d8b586 | 226 | struct inode *upperinode = d_inode(upperdentry); |
e6d2ebdd | 227 | |
bbb1e54d | 228 | WARN_ON(!inode_unhashed(inode)); |
09d8b586 MS |
229 | WARN_ON(!inode_is_locked(upperdentry->d_parent->d_inode)); |
230 | WARN_ON(OVL_I(inode)->__upperdentry); | |
231 | ||
25b7713a | 232 | /* |
09d8b586 | 233 | * Make sure upperdentry is consistent before making it visible |
25b7713a MS |
234 | */ |
235 | smp_wmb(); | |
09d8b586 | 236 | OVL_I(inode)->__upperdentry = upperdentry; |
25b7713a MS |
237 | if (!S_ISDIR(upperinode->i_mode)) { |
238 | inode->i_private = upperinode; | |
bbb1e54d | 239 | __insert_inode_hash(inode, (unsigned long) upperinode); |
25b7713a | 240 | } |
bbb1e54d MS |
241 | } |
242 | ||
243 | void ovl_dentry_version_inc(struct dentry *dentry) | |
244 | { | |
245 | struct ovl_entry *oe = dentry->d_fsdata; | |
246 | ||
247 | WARN_ON(!inode_is_locked(dentry->d_inode)); | |
248 | oe->version++; | |
249 | } | |
250 | ||
251 | u64 ovl_dentry_version_get(struct dentry *dentry) | |
252 | { | |
253 | struct ovl_entry *oe = dentry->d_fsdata; | |
254 | ||
255 | WARN_ON(!inode_is_locked(dentry->d_inode)); | |
256 | return oe->version; | |
257 | } | |
258 | ||
259 | bool ovl_is_whiteout(struct dentry *dentry) | |
260 | { | |
261 | struct inode *inode = dentry->d_inode; | |
262 | ||
263 | return inode && IS_WHITEOUT(inode); | |
264 | } | |
265 | ||
266 | struct file *ovl_path_open(struct path *path, int flags) | |
267 | { | |
268 | return dentry_open(path, flags | O_NOATIME, current_cred()); | |
269 | } | |
39d3d60a AG |
270 | |
271 | int ovl_copy_up_start(struct dentry *dentry) | |
272 | { | |
a015dafc | 273 | struct ovl_inode *oi = OVL_I(d_inode(dentry)); |
39d3d60a AG |
274 | int err; |
275 | ||
a015dafc AG |
276 | err = mutex_lock_interruptible(&oi->lock); |
277 | if (!err && ovl_dentry_upper(dentry)) { | |
278 | err = 1; /* Already copied up */ | |
279 | mutex_unlock(&oi->lock); | |
39d3d60a | 280 | } |
39d3d60a AG |
281 | |
282 | return err; | |
283 | } | |
284 | ||
285 | void ovl_copy_up_end(struct dentry *dentry) | |
286 | { | |
a015dafc | 287 | mutex_unlock(&OVL_I(d_inode(dentry))->lock); |
39d3d60a | 288 | } |
82b749b2 | 289 | |
f3a15685 AG |
290 | bool ovl_check_dir_xattr(struct dentry *dentry, const char *name) |
291 | { | |
292 | int res; | |
293 | char val; | |
294 | ||
295 | if (!d_is_dir(dentry)) | |
296 | return false; | |
297 | ||
298 | res = vfs_getxattr(dentry, name, &val, 1); | |
299 | if (res == 1 && val == 'y') | |
300 | return true; | |
301 | ||
302 | return false; | |
303 | } | |
304 | ||
82b749b2 AG |
305 | int ovl_check_setxattr(struct dentry *dentry, struct dentry *upperdentry, |
306 | const char *name, const void *value, size_t size, | |
307 | int xerr) | |
308 | { | |
309 | int err; | |
310 | struct ovl_fs *ofs = dentry->d_sb->s_fs_info; | |
311 | ||
312 | if (ofs->noxattr) | |
313 | return xerr; | |
314 | ||
315 | err = ovl_do_setxattr(upperdentry, name, value, size, 0); | |
316 | ||
317 | if (err == -EOPNOTSUPP) { | |
318 | pr_warn("overlayfs: cannot set %s xattr on upper\n", name); | |
319 | ofs->noxattr = true; | |
320 | return xerr; | |
321 | } | |
322 | ||
323 | return err; | |
324 | } | |
f3a15685 AG |
325 | |
326 | int ovl_set_impure(struct dentry *dentry, struct dentry *upperdentry) | |
327 | { | |
328 | int err; | |
f3a15685 | 329 | |
13c72075 | 330 | if (ovl_test_flag(OVL_IMPURE, d_inode(dentry))) |
f3a15685 AG |
331 | return 0; |
332 | ||
333 | /* | |
334 | * Do not fail when upper doesn't support xattrs. | |
335 | * Upper inodes won't have origin nor redirect xattr anyway. | |
336 | */ | |
337 | err = ovl_check_setxattr(dentry, upperdentry, OVL_XATTR_IMPURE, | |
338 | "y", 1, 0); | |
339 | if (!err) | |
13c72075 | 340 | ovl_set_flag(OVL_IMPURE, d_inode(dentry)); |
f3a15685 AG |
341 | |
342 | return err; | |
343 | } | |
13c72075 MS |
344 | |
345 | void ovl_set_flag(unsigned long flag, struct inode *inode) | |
346 | { | |
347 | set_bit(flag, &OVL_I(inode)->flags); | |
348 | } | |
349 | ||
350 | bool ovl_test_flag(unsigned long flag, struct inode *inode) | |
351 | { | |
352 | return test_bit(flag, &OVL_I(inode)->flags); | |
353 | } |