Commit 9f2f7d4c8dfcf4617af5de6ea381b91deac3db48
Committed by
Al Viro
1 parent
b2de525f09
Exists in
ti-lsk-linux-4.1.y
and in
10 other branches
ovl: initialize ->is_cursor
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Showing 1 changed file with 1 additions and 0 deletions Inline Diff
fs/overlayfs/readdir.c
1 | /* | 1 | /* |
2 | * | 2 | * |
3 | * Copyright (C) 2011 Novell Inc. | 3 | * Copyright (C) 2011 Novell Inc. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify it | 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 | 6 | * under the terms of the GNU General Public License version 2 as published by |
7 | * the Free Software Foundation. | 7 | * the Free Software Foundation. |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <linux/fs.h> | 10 | #include <linux/fs.h> |
11 | #include <linux/slab.h> | 11 | #include <linux/slab.h> |
12 | #include <linux/namei.h> | 12 | #include <linux/namei.h> |
13 | #include <linux/file.h> | 13 | #include <linux/file.h> |
14 | #include <linux/xattr.h> | 14 | #include <linux/xattr.h> |
15 | #include <linux/rbtree.h> | 15 | #include <linux/rbtree.h> |
16 | #include <linux/security.h> | 16 | #include <linux/security.h> |
17 | #include <linux/cred.h> | 17 | #include <linux/cred.h> |
18 | #include "overlayfs.h" | 18 | #include "overlayfs.h" |
19 | 19 | ||
20 | struct ovl_cache_entry { | 20 | struct ovl_cache_entry { |
21 | unsigned int len; | 21 | unsigned int len; |
22 | unsigned int type; | 22 | unsigned int type; |
23 | u64 ino; | 23 | u64 ino; |
24 | struct list_head l_node; | 24 | struct list_head l_node; |
25 | struct rb_node node; | 25 | struct rb_node node; |
26 | bool is_whiteout; | 26 | bool is_whiteout; |
27 | bool is_cursor; | 27 | bool is_cursor; |
28 | char name[]; | 28 | char name[]; |
29 | }; | 29 | }; |
30 | 30 | ||
31 | struct ovl_dir_cache { | 31 | struct ovl_dir_cache { |
32 | long refcount; | 32 | long refcount; |
33 | u64 version; | 33 | u64 version; |
34 | struct list_head entries; | 34 | struct list_head entries; |
35 | }; | 35 | }; |
36 | 36 | ||
37 | struct ovl_readdir_data { | 37 | struct ovl_readdir_data { |
38 | struct dir_context ctx; | 38 | struct dir_context ctx; |
39 | bool is_merge; | 39 | bool is_merge; |
40 | struct rb_root root; | 40 | struct rb_root root; |
41 | struct list_head *list; | 41 | struct list_head *list; |
42 | struct list_head middle; | 42 | struct list_head middle; |
43 | int count; | 43 | int count; |
44 | int err; | 44 | int err; |
45 | }; | 45 | }; |
46 | 46 | ||
47 | struct ovl_dir_file { | 47 | struct ovl_dir_file { |
48 | bool is_real; | 48 | bool is_real; |
49 | bool is_upper; | 49 | bool is_upper; |
50 | struct ovl_dir_cache *cache; | 50 | struct ovl_dir_cache *cache; |
51 | struct ovl_cache_entry cursor; | 51 | struct ovl_cache_entry cursor; |
52 | struct file *realfile; | 52 | struct file *realfile; |
53 | struct file *upperfile; | 53 | struct file *upperfile; |
54 | }; | 54 | }; |
55 | 55 | ||
56 | static struct ovl_cache_entry *ovl_cache_entry_from_node(struct rb_node *n) | 56 | static struct ovl_cache_entry *ovl_cache_entry_from_node(struct rb_node *n) |
57 | { | 57 | { |
58 | return container_of(n, struct ovl_cache_entry, node); | 58 | return container_of(n, struct ovl_cache_entry, node); |
59 | } | 59 | } |
60 | 60 | ||
61 | static struct ovl_cache_entry *ovl_cache_entry_find(struct rb_root *root, | 61 | static struct ovl_cache_entry *ovl_cache_entry_find(struct rb_root *root, |
62 | const char *name, int len) | 62 | const char *name, int len) |
63 | { | 63 | { |
64 | struct rb_node *node = root->rb_node; | 64 | struct rb_node *node = root->rb_node; |
65 | int cmp; | 65 | int cmp; |
66 | 66 | ||
67 | while (node) { | 67 | while (node) { |
68 | struct ovl_cache_entry *p = ovl_cache_entry_from_node(node); | 68 | struct ovl_cache_entry *p = ovl_cache_entry_from_node(node); |
69 | 69 | ||
70 | cmp = strncmp(name, p->name, len); | 70 | cmp = strncmp(name, p->name, len); |
71 | if (cmp > 0) | 71 | if (cmp > 0) |
72 | node = p->node.rb_right; | 72 | node = p->node.rb_right; |
73 | else if (cmp < 0 || len < p->len) | 73 | else if (cmp < 0 || len < p->len) |
74 | node = p->node.rb_left; | 74 | node = p->node.rb_left; |
75 | else | 75 | else |
76 | return p; | 76 | return p; |
77 | } | 77 | } |
78 | 78 | ||
79 | return NULL; | 79 | return NULL; |
80 | } | 80 | } |
81 | 81 | ||
82 | static struct ovl_cache_entry *ovl_cache_entry_new(const char *name, int len, | 82 | static struct ovl_cache_entry *ovl_cache_entry_new(const char *name, int len, |
83 | u64 ino, unsigned int d_type) | 83 | u64 ino, unsigned int d_type) |
84 | { | 84 | { |
85 | struct ovl_cache_entry *p; | 85 | struct ovl_cache_entry *p; |
86 | size_t size = offsetof(struct ovl_cache_entry, name[len + 1]); | 86 | size_t size = offsetof(struct ovl_cache_entry, name[len + 1]); |
87 | 87 | ||
88 | p = kmalloc(size, GFP_KERNEL); | 88 | p = kmalloc(size, GFP_KERNEL); |
89 | if (p) { | 89 | if (p) { |
90 | memcpy(p->name, name, len); | 90 | memcpy(p->name, name, len); |
91 | p->name[len] = '\0'; | 91 | p->name[len] = '\0'; |
92 | p->len = len; | 92 | p->len = len; |
93 | p->type = d_type; | 93 | p->type = d_type; |
94 | p->ino = ino; | 94 | p->ino = ino; |
95 | p->is_whiteout = false; | 95 | p->is_whiteout = false; |
96 | p->is_cursor = false; | ||
96 | } | 97 | } |
97 | 98 | ||
98 | return p; | 99 | return p; |
99 | } | 100 | } |
100 | 101 | ||
101 | static int ovl_cache_entry_add_rb(struct ovl_readdir_data *rdd, | 102 | static int ovl_cache_entry_add_rb(struct ovl_readdir_data *rdd, |
102 | const char *name, int len, u64 ino, | 103 | const char *name, int len, u64 ino, |
103 | unsigned int d_type) | 104 | unsigned int d_type) |
104 | { | 105 | { |
105 | struct rb_node **newp = &rdd->root.rb_node; | 106 | struct rb_node **newp = &rdd->root.rb_node; |
106 | struct rb_node *parent = NULL; | 107 | struct rb_node *parent = NULL; |
107 | struct ovl_cache_entry *p; | 108 | struct ovl_cache_entry *p; |
108 | 109 | ||
109 | while (*newp) { | 110 | while (*newp) { |
110 | int cmp; | 111 | int cmp; |
111 | struct ovl_cache_entry *tmp; | 112 | struct ovl_cache_entry *tmp; |
112 | 113 | ||
113 | parent = *newp; | 114 | parent = *newp; |
114 | tmp = ovl_cache_entry_from_node(*newp); | 115 | tmp = ovl_cache_entry_from_node(*newp); |
115 | cmp = strncmp(name, tmp->name, len); | 116 | cmp = strncmp(name, tmp->name, len); |
116 | if (cmp > 0) | 117 | if (cmp > 0) |
117 | newp = &tmp->node.rb_right; | 118 | newp = &tmp->node.rb_right; |
118 | else if (cmp < 0 || len < tmp->len) | 119 | else if (cmp < 0 || len < tmp->len) |
119 | newp = &tmp->node.rb_left; | 120 | newp = &tmp->node.rb_left; |
120 | else | 121 | else |
121 | return 0; | 122 | return 0; |
122 | } | 123 | } |
123 | 124 | ||
124 | p = ovl_cache_entry_new(name, len, ino, d_type); | 125 | p = ovl_cache_entry_new(name, len, ino, d_type); |
125 | if (p == NULL) | 126 | if (p == NULL) |
126 | return -ENOMEM; | 127 | return -ENOMEM; |
127 | 128 | ||
128 | list_add_tail(&p->l_node, rdd->list); | 129 | list_add_tail(&p->l_node, rdd->list); |
129 | rb_link_node(&p->node, parent, newp); | 130 | rb_link_node(&p->node, parent, newp); |
130 | rb_insert_color(&p->node, &rdd->root); | 131 | rb_insert_color(&p->node, &rdd->root); |
131 | 132 | ||
132 | return 0; | 133 | return 0; |
133 | } | 134 | } |
134 | 135 | ||
135 | static int ovl_fill_lower(struct ovl_readdir_data *rdd, | 136 | static int ovl_fill_lower(struct ovl_readdir_data *rdd, |
136 | const char *name, int namelen, | 137 | const char *name, int namelen, |
137 | loff_t offset, u64 ino, unsigned int d_type) | 138 | loff_t offset, u64 ino, unsigned int d_type) |
138 | { | 139 | { |
139 | struct ovl_cache_entry *p; | 140 | struct ovl_cache_entry *p; |
140 | 141 | ||
141 | p = ovl_cache_entry_find(&rdd->root, name, namelen); | 142 | p = ovl_cache_entry_find(&rdd->root, name, namelen); |
142 | if (p) { | 143 | if (p) { |
143 | list_move_tail(&p->l_node, &rdd->middle); | 144 | list_move_tail(&p->l_node, &rdd->middle); |
144 | } else { | 145 | } else { |
145 | p = ovl_cache_entry_new(name, namelen, ino, d_type); | 146 | p = ovl_cache_entry_new(name, namelen, ino, d_type); |
146 | if (p == NULL) | 147 | if (p == NULL) |
147 | rdd->err = -ENOMEM; | 148 | rdd->err = -ENOMEM; |
148 | else | 149 | else |
149 | list_add_tail(&p->l_node, &rdd->middle); | 150 | list_add_tail(&p->l_node, &rdd->middle); |
150 | } | 151 | } |
151 | 152 | ||
152 | return rdd->err; | 153 | return rdd->err; |
153 | } | 154 | } |
154 | 155 | ||
155 | void ovl_cache_free(struct list_head *list) | 156 | void ovl_cache_free(struct list_head *list) |
156 | { | 157 | { |
157 | struct ovl_cache_entry *p; | 158 | struct ovl_cache_entry *p; |
158 | struct ovl_cache_entry *n; | 159 | struct ovl_cache_entry *n; |
159 | 160 | ||
160 | list_for_each_entry_safe(p, n, list, l_node) | 161 | list_for_each_entry_safe(p, n, list, l_node) |
161 | kfree(p); | 162 | kfree(p); |
162 | 163 | ||
163 | INIT_LIST_HEAD(list); | 164 | INIT_LIST_HEAD(list); |
164 | } | 165 | } |
165 | 166 | ||
166 | static void ovl_cache_put(struct ovl_dir_file *od, struct dentry *dentry) | 167 | static void ovl_cache_put(struct ovl_dir_file *od, struct dentry *dentry) |
167 | { | 168 | { |
168 | struct ovl_dir_cache *cache = od->cache; | 169 | struct ovl_dir_cache *cache = od->cache; |
169 | 170 | ||
170 | list_del(&od->cursor.l_node); | 171 | list_del(&od->cursor.l_node); |
171 | WARN_ON(cache->refcount <= 0); | 172 | WARN_ON(cache->refcount <= 0); |
172 | cache->refcount--; | 173 | cache->refcount--; |
173 | if (!cache->refcount) { | 174 | if (!cache->refcount) { |
174 | if (ovl_dir_cache(dentry) == cache) | 175 | if (ovl_dir_cache(dentry) == cache) |
175 | ovl_set_dir_cache(dentry, NULL); | 176 | ovl_set_dir_cache(dentry, NULL); |
176 | 177 | ||
177 | ovl_cache_free(&cache->entries); | 178 | ovl_cache_free(&cache->entries); |
178 | kfree(cache); | 179 | kfree(cache); |
179 | } | 180 | } |
180 | } | 181 | } |
181 | 182 | ||
182 | static int ovl_fill_merge(void *buf, const char *name, int namelen, | 183 | static int ovl_fill_merge(void *buf, const char *name, int namelen, |
183 | loff_t offset, u64 ino, unsigned int d_type) | 184 | loff_t offset, u64 ino, unsigned int d_type) |
184 | { | 185 | { |
185 | struct ovl_readdir_data *rdd = buf; | 186 | struct ovl_readdir_data *rdd = buf; |
186 | 187 | ||
187 | rdd->count++; | 188 | rdd->count++; |
188 | if (!rdd->is_merge) | 189 | if (!rdd->is_merge) |
189 | return ovl_cache_entry_add_rb(rdd, name, namelen, ino, d_type); | 190 | return ovl_cache_entry_add_rb(rdd, name, namelen, ino, d_type); |
190 | else | 191 | else |
191 | return ovl_fill_lower(rdd, name, namelen, offset, ino, d_type); | 192 | return ovl_fill_lower(rdd, name, namelen, offset, ino, d_type); |
192 | } | 193 | } |
193 | 194 | ||
194 | static inline int ovl_dir_read(struct path *realpath, | 195 | static inline int ovl_dir_read(struct path *realpath, |
195 | struct ovl_readdir_data *rdd) | 196 | struct ovl_readdir_data *rdd) |
196 | { | 197 | { |
197 | struct file *realfile; | 198 | struct file *realfile; |
198 | int err; | 199 | int err; |
199 | 200 | ||
200 | realfile = ovl_path_open(realpath, O_RDONLY | O_DIRECTORY); | 201 | realfile = ovl_path_open(realpath, O_RDONLY | O_DIRECTORY); |
201 | if (IS_ERR(realfile)) | 202 | if (IS_ERR(realfile)) |
202 | return PTR_ERR(realfile); | 203 | return PTR_ERR(realfile); |
203 | 204 | ||
204 | rdd->ctx.pos = 0; | 205 | rdd->ctx.pos = 0; |
205 | do { | 206 | do { |
206 | rdd->count = 0; | 207 | rdd->count = 0; |
207 | rdd->err = 0; | 208 | rdd->err = 0; |
208 | err = iterate_dir(realfile, &rdd->ctx); | 209 | err = iterate_dir(realfile, &rdd->ctx); |
209 | if (err >= 0) | 210 | if (err >= 0) |
210 | err = rdd->err; | 211 | err = rdd->err; |
211 | } while (!err && rdd->count); | 212 | } while (!err && rdd->count); |
212 | fput(realfile); | 213 | fput(realfile); |
213 | 214 | ||
214 | return err; | 215 | return err; |
215 | } | 216 | } |
216 | 217 | ||
217 | static void ovl_dir_reset(struct file *file) | 218 | static void ovl_dir_reset(struct file *file) |
218 | { | 219 | { |
219 | struct ovl_dir_file *od = file->private_data; | 220 | struct ovl_dir_file *od = file->private_data; |
220 | struct ovl_dir_cache *cache = od->cache; | 221 | struct ovl_dir_cache *cache = od->cache; |
221 | struct dentry *dentry = file->f_path.dentry; | 222 | struct dentry *dentry = file->f_path.dentry; |
222 | enum ovl_path_type type = ovl_path_type(dentry); | 223 | enum ovl_path_type type = ovl_path_type(dentry); |
223 | 224 | ||
224 | if (cache && ovl_dentry_version_get(dentry) != cache->version) { | 225 | if (cache && ovl_dentry_version_get(dentry) != cache->version) { |
225 | ovl_cache_put(od, dentry); | 226 | ovl_cache_put(od, dentry); |
226 | od->cache = NULL; | 227 | od->cache = NULL; |
227 | } | 228 | } |
228 | WARN_ON(!od->is_real && type != OVL_PATH_MERGE); | 229 | WARN_ON(!od->is_real && type != OVL_PATH_MERGE); |
229 | if (od->is_real && type == OVL_PATH_MERGE) | 230 | if (od->is_real && type == OVL_PATH_MERGE) |
230 | od->is_real = false; | 231 | od->is_real = false; |
231 | } | 232 | } |
232 | 233 | ||
233 | static int ovl_dir_mark_whiteouts(struct dentry *dir, | 234 | static int ovl_dir_mark_whiteouts(struct dentry *dir, |
234 | struct ovl_readdir_data *rdd) | 235 | struct ovl_readdir_data *rdd) |
235 | { | 236 | { |
236 | struct ovl_cache_entry *p; | 237 | struct ovl_cache_entry *p; |
237 | struct dentry *dentry; | 238 | struct dentry *dentry; |
238 | const struct cred *old_cred; | 239 | const struct cred *old_cred; |
239 | struct cred *override_cred; | 240 | struct cred *override_cred; |
240 | 241 | ||
241 | override_cred = prepare_creds(); | 242 | override_cred = prepare_creds(); |
242 | if (!override_cred) { | 243 | if (!override_cred) { |
243 | ovl_cache_free(rdd->list); | 244 | ovl_cache_free(rdd->list); |
244 | return -ENOMEM; | 245 | return -ENOMEM; |
245 | } | 246 | } |
246 | 247 | ||
247 | /* | 248 | /* |
248 | * CAP_DAC_OVERRIDE for lookup | 249 | * CAP_DAC_OVERRIDE for lookup |
249 | */ | 250 | */ |
250 | cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE); | 251 | cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE); |
251 | old_cred = override_creds(override_cred); | 252 | old_cred = override_creds(override_cred); |
252 | 253 | ||
253 | mutex_lock(&dir->d_inode->i_mutex); | 254 | mutex_lock(&dir->d_inode->i_mutex); |
254 | list_for_each_entry(p, rdd->list, l_node) { | 255 | list_for_each_entry(p, rdd->list, l_node) { |
255 | if (p->is_cursor) | 256 | if (p->is_cursor) |
256 | continue; | 257 | continue; |
257 | 258 | ||
258 | if (p->type != DT_CHR) | 259 | if (p->type != DT_CHR) |
259 | continue; | 260 | continue; |
260 | 261 | ||
261 | dentry = lookup_one_len(p->name, dir, p->len); | 262 | dentry = lookup_one_len(p->name, dir, p->len); |
262 | if (IS_ERR(dentry)) | 263 | if (IS_ERR(dentry)) |
263 | continue; | 264 | continue; |
264 | 265 | ||
265 | p->is_whiteout = ovl_is_whiteout(dentry); | 266 | p->is_whiteout = ovl_is_whiteout(dentry); |
266 | dput(dentry); | 267 | dput(dentry); |
267 | } | 268 | } |
268 | mutex_unlock(&dir->d_inode->i_mutex); | 269 | mutex_unlock(&dir->d_inode->i_mutex); |
269 | 270 | ||
270 | revert_creds(old_cred); | 271 | revert_creds(old_cred); |
271 | put_cred(override_cred); | 272 | put_cred(override_cred); |
272 | 273 | ||
273 | return 0; | 274 | return 0; |
274 | } | 275 | } |
275 | 276 | ||
276 | static inline int ovl_dir_read_merged(struct path *upperpath, | 277 | static inline int ovl_dir_read_merged(struct path *upperpath, |
277 | struct path *lowerpath, | 278 | struct path *lowerpath, |
278 | struct list_head *list) | 279 | struct list_head *list) |
279 | { | 280 | { |
280 | int err; | 281 | int err; |
281 | struct ovl_readdir_data rdd = { | 282 | struct ovl_readdir_data rdd = { |
282 | .ctx.actor = ovl_fill_merge, | 283 | .ctx.actor = ovl_fill_merge, |
283 | .list = list, | 284 | .list = list, |
284 | .root = RB_ROOT, | 285 | .root = RB_ROOT, |
285 | .is_merge = false, | 286 | .is_merge = false, |
286 | }; | 287 | }; |
287 | 288 | ||
288 | if (upperpath->dentry) { | 289 | if (upperpath->dentry) { |
289 | err = ovl_dir_read(upperpath, &rdd); | 290 | err = ovl_dir_read(upperpath, &rdd); |
290 | if (err) | 291 | if (err) |
291 | goto out; | 292 | goto out; |
292 | 293 | ||
293 | if (lowerpath->dentry) { | 294 | if (lowerpath->dentry) { |
294 | err = ovl_dir_mark_whiteouts(upperpath->dentry, &rdd); | 295 | err = ovl_dir_mark_whiteouts(upperpath->dentry, &rdd); |
295 | if (err) | 296 | if (err) |
296 | goto out; | 297 | goto out; |
297 | } | 298 | } |
298 | } | 299 | } |
299 | if (lowerpath->dentry) { | 300 | if (lowerpath->dentry) { |
300 | /* | 301 | /* |
301 | * Insert lowerpath entries before upperpath ones, this allows | 302 | * Insert lowerpath entries before upperpath ones, this allows |
302 | * offsets to be reasonably constant | 303 | * offsets to be reasonably constant |
303 | */ | 304 | */ |
304 | list_add(&rdd.middle, rdd.list); | 305 | list_add(&rdd.middle, rdd.list); |
305 | rdd.is_merge = true; | 306 | rdd.is_merge = true; |
306 | err = ovl_dir_read(lowerpath, &rdd); | 307 | err = ovl_dir_read(lowerpath, &rdd); |
307 | list_del(&rdd.middle); | 308 | list_del(&rdd.middle); |
308 | } | 309 | } |
309 | out: | 310 | out: |
310 | return err; | 311 | return err; |
311 | } | 312 | } |
312 | 313 | ||
313 | static void ovl_seek_cursor(struct ovl_dir_file *od, loff_t pos) | 314 | static void ovl_seek_cursor(struct ovl_dir_file *od, loff_t pos) |
314 | { | 315 | { |
315 | struct ovl_cache_entry *p; | 316 | struct ovl_cache_entry *p; |
316 | loff_t off = 0; | 317 | loff_t off = 0; |
317 | 318 | ||
318 | list_for_each_entry(p, &od->cache->entries, l_node) { | 319 | list_for_each_entry(p, &od->cache->entries, l_node) { |
319 | if (p->is_cursor) | 320 | if (p->is_cursor) |
320 | continue; | 321 | continue; |
321 | if (off >= pos) | 322 | if (off >= pos) |
322 | break; | 323 | break; |
323 | off++; | 324 | off++; |
324 | } | 325 | } |
325 | list_move_tail(&od->cursor.l_node, &p->l_node); | 326 | list_move_tail(&od->cursor.l_node, &p->l_node); |
326 | } | 327 | } |
327 | 328 | ||
328 | static struct ovl_dir_cache *ovl_cache_get(struct dentry *dentry) | 329 | static struct ovl_dir_cache *ovl_cache_get(struct dentry *dentry) |
329 | { | 330 | { |
330 | int res; | 331 | int res; |
331 | struct path lowerpath; | 332 | struct path lowerpath; |
332 | struct path upperpath; | 333 | struct path upperpath; |
333 | struct ovl_dir_cache *cache; | 334 | struct ovl_dir_cache *cache; |
334 | 335 | ||
335 | cache = ovl_dir_cache(dentry); | 336 | cache = ovl_dir_cache(dentry); |
336 | if (cache && ovl_dentry_version_get(dentry) == cache->version) { | 337 | if (cache && ovl_dentry_version_get(dentry) == cache->version) { |
337 | cache->refcount++; | 338 | cache->refcount++; |
338 | return cache; | 339 | return cache; |
339 | } | 340 | } |
340 | ovl_set_dir_cache(dentry, NULL); | 341 | ovl_set_dir_cache(dentry, NULL); |
341 | 342 | ||
342 | cache = kzalloc(sizeof(struct ovl_dir_cache), GFP_KERNEL); | 343 | cache = kzalloc(sizeof(struct ovl_dir_cache), GFP_KERNEL); |
343 | if (!cache) | 344 | if (!cache) |
344 | return ERR_PTR(-ENOMEM); | 345 | return ERR_PTR(-ENOMEM); |
345 | 346 | ||
346 | cache->refcount = 1; | 347 | cache->refcount = 1; |
347 | INIT_LIST_HEAD(&cache->entries); | 348 | INIT_LIST_HEAD(&cache->entries); |
348 | 349 | ||
349 | ovl_path_lower(dentry, &lowerpath); | 350 | ovl_path_lower(dentry, &lowerpath); |
350 | ovl_path_upper(dentry, &upperpath); | 351 | ovl_path_upper(dentry, &upperpath); |
351 | 352 | ||
352 | res = ovl_dir_read_merged(&upperpath, &lowerpath, &cache->entries); | 353 | res = ovl_dir_read_merged(&upperpath, &lowerpath, &cache->entries); |
353 | if (res) { | 354 | if (res) { |
354 | ovl_cache_free(&cache->entries); | 355 | ovl_cache_free(&cache->entries); |
355 | kfree(cache); | 356 | kfree(cache); |
356 | return ERR_PTR(res); | 357 | return ERR_PTR(res); |
357 | } | 358 | } |
358 | 359 | ||
359 | cache->version = ovl_dentry_version_get(dentry); | 360 | cache->version = ovl_dentry_version_get(dentry); |
360 | ovl_set_dir_cache(dentry, cache); | 361 | ovl_set_dir_cache(dentry, cache); |
361 | 362 | ||
362 | return cache; | 363 | return cache; |
363 | } | 364 | } |
364 | 365 | ||
365 | static int ovl_iterate(struct file *file, struct dir_context *ctx) | 366 | static int ovl_iterate(struct file *file, struct dir_context *ctx) |
366 | { | 367 | { |
367 | struct ovl_dir_file *od = file->private_data; | 368 | struct ovl_dir_file *od = file->private_data; |
368 | struct dentry *dentry = file->f_path.dentry; | 369 | struct dentry *dentry = file->f_path.dentry; |
369 | 370 | ||
370 | if (!ctx->pos) | 371 | if (!ctx->pos) |
371 | ovl_dir_reset(file); | 372 | ovl_dir_reset(file); |
372 | 373 | ||
373 | if (od->is_real) | 374 | if (od->is_real) |
374 | return iterate_dir(od->realfile, ctx); | 375 | return iterate_dir(od->realfile, ctx); |
375 | 376 | ||
376 | if (!od->cache) { | 377 | if (!od->cache) { |
377 | struct ovl_dir_cache *cache; | 378 | struct ovl_dir_cache *cache; |
378 | 379 | ||
379 | cache = ovl_cache_get(dentry); | 380 | cache = ovl_cache_get(dentry); |
380 | if (IS_ERR(cache)) | 381 | if (IS_ERR(cache)) |
381 | return PTR_ERR(cache); | 382 | return PTR_ERR(cache); |
382 | 383 | ||
383 | od->cache = cache; | 384 | od->cache = cache; |
384 | ovl_seek_cursor(od, ctx->pos); | 385 | ovl_seek_cursor(od, ctx->pos); |
385 | } | 386 | } |
386 | 387 | ||
387 | while (od->cursor.l_node.next != &od->cache->entries) { | 388 | while (od->cursor.l_node.next != &od->cache->entries) { |
388 | struct ovl_cache_entry *p; | 389 | struct ovl_cache_entry *p; |
389 | 390 | ||
390 | p = list_entry(od->cursor.l_node.next, struct ovl_cache_entry, l_node); | 391 | p = list_entry(od->cursor.l_node.next, struct ovl_cache_entry, l_node); |
391 | /* Skip cursors */ | 392 | /* Skip cursors */ |
392 | if (!p->is_cursor) { | 393 | if (!p->is_cursor) { |
393 | if (!p->is_whiteout) { | 394 | if (!p->is_whiteout) { |
394 | if (!dir_emit(ctx, p->name, p->len, p->ino, p->type)) | 395 | if (!dir_emit(ctx, p->name, p->len, p->ino, p->type)) |
395 | break; | 396 | break; |
396 | } | 397 | } |
397 | ctx->pos++; | 398 | ctx->pos++; |
398 | } | 399 | } |
399 | list_move(&od->cursor.l_node, &p->l_node); | 400 | list_move(&od->cursor.l_node, &p->l_node); |
400 | } | 401 | } |
401 | return 0; | 402 | return 0; |
402 | } | 403 | } |
403 | 404 | ||
404 | static loff_t ovl_dir_llseek(struct file *file, loff_t offset, int origin) | 405 | static loff_t ovl_dir_llseek(struct file *file, loff_t offset, int origin) |
405 | { | 406 | { |
406 | loff_t res; | 407 | loff_t res; |
407 | struct ovl_dir_file *od = file->private_data; | 408 | struct ovl_dir_file *od = file->private_data; |
408 | 409 | ||
409 | mutex_lock(&file_inode(file)->i_mutex); | 410 | mutex_lock(&file_inode(file)->i_mutex); |
410 | if (!file->f_pos) | 411 | if (!file->f_pos) |
411 | ovl_dir_reset(file); | 412 | ovl_dir_reset(file); |
412 | 413 | ||
413 | if (od->is_real) { | 414 | if (od->is_real) { |
414 | res = vfs_llseek(od->realfile, offset, origin); | 415 | res = vfs_llseek(od->realfile, offset, origin); |
415 | file->f_pos = od->realfile->f_pos; | 416 | file->f_pos = od->realfile->f_pos; |
416 | } else { | 417 | } else { |
417 | res = -EINVAL; | 418 | res = -EINVAL; |
418 | 419 | ||
419 | switch (origin) { | 420 | switch (origin) { |
420 | case SEEK_CUR: | 421 | case SEEK_CUR: |
421 | offset += file->f_pos; | 422 | offset += file->f_pos; |
422 | break; | 423 | break; |
423 | case SEEK_SET: | 424 | case SEEK_SET: |
424 | break; | 425 | break; |
425 | default: | 426 | default: |
426 | goto out_unlock; | 427 | goto out_unlock; |
427 | } | 428 | } |
428 | if (offset < 0) | 429 | if (offset < 0) |
429 | goto out_unlock; | 430 | goto out_unlock; |
430 | 431 | ||
431 | if (offset != file->f_pos) { | 432 | if (offset != file->f_pos) { |
432 | file->f_pos = offset; | 433 | file->f_pos = offset; |
433 | if (od->cache) | 434 | if (od->cache) |
434 | ovl_seek_cursor(od, offset); | 435 | ovl_seek_cursor(od, offset); |
435 | } | 436 | } |
436 | res = offset; | 437 | res = offset; |
437 | } | 438 | } |
438 | out_unlock: | 439 | out_unlock: |
439 | mutex_unlock(&file_inode(file)->i_mutex); | 440 | mutex_unlock(&file_inode(file)->i_mutex); |
440 | 441 | ||
441 | return res; | 442 | return res; |
442 | } | 443 | } |
443 | 444 | ||
444 | static int ovl_dir_fsync(struct file *file, loff_t start, loff_t end, | 445 | static int ovl_dir_fsync(struct file *file, loff_t start, loff_t end, |
445 | int datasync) | 446 | int datasync) |
446 | { | 447 | { |
447 | struct ovl_dir_file *od = file->private_data; | 448 | struct ovl_dir_file *od = file->private_data; |
448 | struct dentry *dentry = file->f_path.dentry; | 449 | struct dentry *dentry = file->f_path.dentry; |
449 | struct file *realfile = od->realfile; | 450 | struct file *realfile = od->realfile; |
450 | 451 | ||
451 | /* | 452 | /* |
452 | * Need to check if we started out being a lower dir, but got copied up | 453 | * Need to check if we started out being a lower dir, but got copied up |
453 | */ | 454 | */ |
454 | if (!od->is_upper && ovl_path_type(dentry) == OVL_PATH_MERGE) { | 455 | if (!od->is_upper && ovl_path_type(dentry) == OVL_PATH_MERGE) { |
455 | struct inode *inode = file_inode(file); | 456 | struct inode *inode = file_inode(file); |
456 | 457 | ||
457 | realfile =lockless_dereference(od->upperfile); | 458 | realfile =lockless_dereference(od->upperfile); |
458 | if (!realfile) { | 459 | if (!realfile) { |
459 | struct path upperpath; | 460 | struct path upperpath; |
460 | 461 | ||
461 | ovl_path_upper(dentry, &upperpath); | 462 | ovl_path_upper(dentry, &upperpath); |
462 | realfile = ovl_path_open(&upperpath, O_RDONLY); | 463 | realfile = ovl_path_open(&upperpath, O_RDONLY); |
463 | smp_mb__before_spinlock(); | 464 | smp_mb__before_spinlock(); |
464 | mutex_lock(&inode->i_mutex); | 465 | mutex_lock(&inode->i_mutex); |
465 | if (!od->upperfile) { | 466 | if (!od->upperfile) { |
466 | if (IS_ERR(realfile)) { | 467 | if (IS_ERR(realfile)) { |
467 | mutex_unlock(&inode->i_mutex); | 468 | mutex_unlock(&inode->i_mutex); |
468 | return PTR_ERR(realfile); | 469 | return PTR_ERR(realfile); |
469 | } | 470 | } |
470 | od->upperfile = realfile; | 471 | od->upperfile = realfile; |
471 | } else { | 472 | } else { |
472 | /* somebody has beaten us to it */ | 473 | /* somebody has beaten us to it */ |
473 | if (!IS_ERR(realfile)) | 474 | if (!IS_ERR(realfile)) |
474 | fput(realfile); | 475 | fput(realfile); |
475 | realfile = od->upperfile; | 476 | realfile = od->upperfile; |
476 | } | 477 | } |
477 | mutex_unlock(&inode->i_mutex); | 478 | mutex_unlock(&inode->i_mutex); |
478 | } | 479 | } |
479 | } | 480 | } |
480 | 481 | ||
481 | return vfs_fsync_range(realfile, start, end, datasync); | 482 | return vfs_fsync_range(realfile, start, end, datasync); |
482 | } | 483 | } |
483 | 484 | ||
484 | static int ovl_dir_release(struct inode *inode, struct file *file) | 485 | static int ovl_dir_release(struct inode *inode, struct file *file) |
485 | { | 486 | { |
486 | struct ovl_dir_file *od = file->private_data; | 487 | struct ovl_dir_file *od = file->private_data; |
487 | 488 | ||
488 | if (od->cache) { | 489 | if (od->cache) { |
489 | mutex_lock(&inode->i_mutex); | 490 | mutex_lock(&inode->i_mutex); |
490 | ovl_cache_put(od, file->f_path.dentry); | 491 | ovl_cache_put(od, file->f_path.dentry); |
491 | mutex_unlock(&inode->i_mutex); | 492 | mutex_unlock(&inode->i_mutex); |
492 | } | 493 | } |
493 | fput(od->realfile); | 494 | fput(od->realfile); |
494 | if (od->upperfile) | 495 | if (od->upperfile) |
495 | fput(od->upperfile); | 496 | fput(od->upperfile); |
496 | kfree(od); | 497 | kfree(od); |
497 | 498 | ||
498 | return 0; | 499 | return 0; |
499 | } | 500 | } |
500 | 501 | ||
501 | static int ovl_dir_open(struct inode *inode, struct file *file) | 502 | static int ovl_dir_open(struct inode *inode, struct file *file) |
502 | { | 503 | { |
503 | struct path realpath; | 504 | struct path realpath; |
504 | struct file *realfile; | 505 | struct file *realfile; |
505 | struct ovl_dir_file *od; | 506 | struct ovl_dir_file *od; |
506 | enum ovl_path_type type; | 507 | enum ovl_path_type type; |
507 | 508 | ||
508 | od = kzalloc(sizeof(struct ovl_dir_file), GFP_KERNEL); | 509 | od = kzalloc(sizeof(struct ovl_dir_file), GFP_KERNEL); |
509 | if (!od) | 510 | if (!od) |
510 | return -ENOMEM; | 511 | return -ENOMEM; |
511 | 512 | ||
512 | type = ovl_path_real(file->f_path.dentry, &realpath); | 513 | type = ovl_path_real(file->f_path.dentry, &realpath); |
513 | realfile = ovl_path_open(&realpath, file->f_flags); | 514 | realfile = ovl_path_open(&realpath, file->f_flags); |
514 | if (IS_ERR(realfile)) { | 515 | if (IS_ERR(realfile)) { |
515 | kfree(od); | 516 | kfree(od); |
516 | return PTR_ERR(realfile); | 517 | return PTR_ERR(realfile); |
517 | } | 518 | } |
518 | INIT_LIST_HEAD(&od->cursor.l_node); | 519 | INIT_LIST_HEAD(&od->cursor.l_node); |
519 | od->realfile = realfile; | 520 | od->realfile = realfile; |
520 | od->is_real = (type != OVL_PATH_MERGE); | 521 | od->is_real = (type != OVL_PATH_MERGE); |
521 | od->is_upper = (type != OVL_PATH_LOWER); | 522 | od->is_upper = (type != OVL_PATH_LOWER); |
522 | od->cursor.is_cursor = true; | 523 | od->cursor.is_cursor = true; |
523 | file->private_data = od; | 524 | file->private_data = od; |
524 | 525 | ||
525 | return 0; | 526 | return 0; |
526 | } | 527 | } |
527 | 528 | ||
528 | const struct file_operations ovl_dir_operations = { | 529 | const struct file_operations ovl_dir_operations = { |
529 | .read = generic_read_dir, | 530 | .read = generic_read_dir, |
530 | .open = ovl_dir_open, | 531 | .open = ovl_dir_open, |
531 | .iterate = ovl_iterate, | 532 | .iterate = ovl_iterate, |
532 | .llseek = ovl_dir_llseek, | 533 | .llseek = ovl_dir_llseek, |
533 | .fsync = ovl_dir_fsync, | 534 | .fsync = ovl_dir_fsync, |
534 | .release = ovl_dir_release, | 535 | .release = ovl_dir_release, |
535 | }; | 536 | }; |
536 | 537 | ||
537 | int ovl_check_empty_dir(struct dentry *dentry, struct list_head *list) | 538 | int ovl_check_empty_dir(struct dentry *dentry, struct list_head *list) |
538 | { | 539 | { |
539 | int err; | 540 | int err; |
540 | struct path lowerpath; | 541 | struct path lowerpath; |
541 | struct path upperpath; | 542 | struct path upperpath; |
542 | struct ovl_cache_entry *p; | 543 | struct ovl_cache_entry *p; |
543 | 544 | ||
544 | ovl_path_upper(dentry, &upperpath); | 545 | ovl_path_upper(dentry, &upperpath); |
545 | ovl_path_lower(dentry, &lowerpath); | 546 | ovl_path_lower(dentry, &lowerpath); |
546 | 547 | ||
547 | err = ovl_dir_read_merged(&upperpath, &lowerpath, list); | 548 | err = ovl_dir_read_merged(&upperpath, &lowerpath, list); |
548 | if (err) | 549 | if (err) |
549 | return err; | 550 | return err; |
550 | 551 | ||
551 | err = 0; | 552 | err = 0; |
552 | 553 | ||
553 | list_for_each_entry(p, list, l_node) { | 554 | list_for_each_entry(p, list, l_node) { |
554 | if (p->is_whiteout) | 555 | if (p->is_whiteout) |
555 | continue; | 556 | continue; |
556 | 557 | ||
557 | if (p->name[0] == '.') { | 558 | if (p->name[0] == '.') { |
558 | if (p->len == 1) | 559 | if (p->len == 1) |
559 | continue; | 560 | continue; |
560 | if (p->len == 2 && p->name[1] == '.') | 561 | if (p->len == 2 && p->name[1] == '.') |
561 | continue; | 562 | continue; |
562 | } | 563 | } |
563 | err = -ENOTEMPTY; | 564 | err = -ENOTEMPTY; |
564 | break; | 565 | break; |
565 | } | 566 | } |
566 | 567 | ||
567 | return err; | 568 | return err; |
568 | } | 569 | } |
569 | 570 | ||
570 | void ovl_cleanup_whiteouts(struct dentry *upper, struct list_head *list) | 571 | void ovl_cleanup_whiteouts(struct dentry *upper, struct list_head *list) |
571 | { | 572 | { |
572 | struct ovl_cache_entry *p; | 573 | struct ovl_cache_entry *p; |
573 | 574 | ||
574 | mutex_lock_nested(&upper->d_inode->i_mutex, I_MUTEX_CHILD); | 575 | mutex_lock_nested(&upper->d_inode->i_mutex, I_MUTEX_CHILD); |
575 | list_for_each_entry(p, list, l_node) { | 576 | list_for_each_entry(p, list, l_node) { |
576 | struct dentry *dentry; | 577 | struct dentry *dentry; |
577 | 578 | ||
578 | if (!p->is_whiteout) | 579 | if (!p->is_whiteout) |
579 | continue; | 580 | continue; |
580 | 581 | ||
581 | dentry = lookup_one_len(p->name, upper, p->len); | 582 | dentry = lookup_one_len(p->name, upper, p->len); |
582 | if (IS_ERR(dentry)) { | 583 | if (IS_ERR(dentry)) { |
583 | pr_err("overlayfs: lookup '%s/%.*s' failed (%i)\n", | 584 | pr_err("overlayfs: lookup '%s/%.*s' failed (%i)\n", |
584 | upper->d_name.name, p->len, p->name, | 585 | upper->d_name.name, p->len, p->name, |
585 | (int) PTR_ERR(dentry)); | 586 | (int) PTR_ERR(dentry)); |
586 | continue; | 587 | continue; |
587 | } | 588 | } |
588 | ovl_cleanup(upper->d_inode, dentry); | 589 | ovl_cleanup(upper->d_inode, dentry); |
589 | dput(dentry); | 590 | dput(dentry); |
590 | } | 591 | } |
591 | mutex_unlock(&upper->d_inode->i_mutex); | 592 | mutex_unlock(&upper->d_inode->i_mutex); |
592 | } | 593 | } |
593 | 594 |