diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-07-02 14:23:00 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-07-02 14:23:00 -0400 |
commit | 320cd413faefe2d30f4ee9651efddec5141bc95b (patch) | |
tree | 7bd339c24aff9bed4204c3f20f65f692a076db20 | |
parent | a7ba4bf5e7ff6bfe83e41c748b77b49297c1b5d9 (diff) | |
parent | cdb672795876d7bc1870aed9a2d7cb59f43d1d96 (diff) |
Merge branch 'overlayfs-next' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs
Pull overlayfs updates from Miklos Szeredi:
"This relaxes the requirements on the lower layer filesystem: now ones
that implement .d_revalidate, such as NFS, can be used.
Upper layer filesystems still has the "no .d_revalidate" requirement.
Also a bad interaction with jffs2 locking has been fixed"
* 'overlayfs-next' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs:
ovl: lookup whiteouts outside iterate_dir()
ovl: allow distributed fs as lower layer
ovl: don't traverse automount points
-rw-r--r-- | fs/overlayfs/readdir.c | 77 | ||||
-rw-r--r-- | fs/overlayfs/super.c | 113 |
2 files changed, 139 insertions, 51 deletions
diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c index 907870e81a72..70e9af551600 100644 --- a/fs/overlayfs/readdir.c +++ b/fs/overlayfs/readdir.c | |||
@@ -23,6 +23,7 @@ struct ovl_cache_entry { | |||
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 | struct ovl_cache_entry *next_maybe_whiteout; | ||
26 | bool is_whiteout; | 27 | bool is_whiteout; |
27 | char name[]; | 28 | char name[]; |
28 | }; | 29 | }; |
@@ -39,7 +40,7 @@ struct ovl_readdir_data { | |||
39 | struct rb_root root; | 40 | struct rb_root root; |
40 | struct list_head *list; | 41 | struct list_head *list; |
41 | struct list_head middle; | 42 | struct list_head middle; |
42 | struct dentry *dir; | 43 | struct ovl_cache_entry *first_maybe_whiteout; |
43 | int count; | 44 | int count; |
44 | int err; | 45 | int err; |
45 | }; | 46 | }; |
@@ -79,7 +80,7 @@ static struct ovl_cache_entry *ovl_cache_entry_find(struct rb_root *root, | |||
79 | return NULL; | 80 | return NULL; |
80 | } | 81 | } |
81 | 82 | ||
82 | static struct ovl_cache_entry *ovl_cache_entry_new(struct dentry *dir, | 83 | static struct ovl_cache_entry *ovl_cache_entry_new(struct ovl_readdir_data *rdd, |
83 | const char *name, int len, | 84 | const char *name, int len, |
84 | u64 ino, unsigned int d_type) | 85 | u64 ino, unsigned int d_type) |
85 | { | 86 | { |
@@ -98,29 +99,8 @@ static struct ovl_cache_entry *ovl_cache_entry_new(struct dentry *dir, | |||
98 | p->is_whiteout = false; | 99 | p->is_whiteout = false; |
99 | 100 | ||
100 | if (d_type == DT_CHR) { | 101 | if (d_type == DT_CHR) { |
101 | struct dentry *dentry; | 102 | p->next_maybe_whiteout = rdd->first_maybe_whiteout; |
102 | const struct cred *old_cred; | 103 | rdd->first_maybe_whiteout = p; |
103 | struct cred *override_cred; | ||
104 | |||
105 | override_cred = prepare_creds(); | ||
106 | if (!override_cred) { | ||
107 | kfree(p); | ||
108 | return NULL; | ||
109 | } | ||
110 | |||
111 | /* | ||
112 | * CAP_DAC_OVERRIDE for lookup | ||
113 | */ | ||
114 | cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE); | ||
115 | old_cred = override_creds(override_cred); | ||
116 | |||
117 | dentry = lookup_one_len(name, dir, len); | ||
118 | if (!IS_ERR(dentry)) { | ||
119 | p->is_whiteout = ovl_is_whiteout(dentry); | ||
120 | dput(dentry); | ||
121 | } | ||
122 | revert_creds(old_cred); | ||
123 | put_cred(override_cred); | ||
124 | } | 104 | } |
125 | return p; | 105 | return p; |
126 | } | 106 | } |
@@ -148,7 +128,7 @@ static int ovl_cache_entry_add_rb(struct ovl_readdir_data *rdd, | |||
148 | return 0; | 128 | return 0; |
149 | } | 129 | } |
150 | 130 | ||
151 | p = ovl_cache_entry_new(rdd->dir, name, len, ino, d_type); | 131 | p = ovl_cache_entry_new(rdd, name, len, ino, d_type); |
152 | if (p == NULL) | 132 | if (p == NULL) |
153 | return -ENOMEM; | 133 | return -ENOMEM; |
154 | 134 | ||
@@ -169,7 +149,7 @@ static int ovl_fill_lower(struct ovl_readdir_data *rdd, | |||
169 | if (p) { | 149 | if (p) { |
170 | list_move_tail(&p->l_node, &rdd->middle); | 150 | list_move_tail(&p->l_node, &rdd->middle); |
171 | } else { | 151 | } else { |
172 | p = ovl_cache_entry_new(rdd->dir, name, namelen, ino, d_type); | 152 | p = ovl_cache_entry_new(rdd, name, namelen, ino, d_type); |
173 | if (p == NULL) | 153 | if (p == NULL) |
174 | rdd->err = -ENOMEM; | 154 | rdd->err = -ENOMEM; |
175 | else | 155 | else |
@@ -219,6 +199,43 @@ static int ovl_fill_merge(struct dir_context *ctx, const char *name, | |||
219 | return ovl_fill_lower(rdd, name, namelen, offset, ino, d_type); | 199 | return ovl_fill_lower(rdd, name, namelen, offset, ino, d_type); |
220 | } | 200 | } |
221 | 201 | ||
202 | static int ovl_check_whiteouts(struct dentry *dir, struct ovl_readdir_data *rdd) | ||
203 | { | ||
204 | int err; | ||
205 | struct ovl_cache_entry *p; | ||
206 | struct dentry *dentry; | ||
207 | const struct cred *old_cred; | ||
208 | struct cred *override_cred; | ||
209 | |||
210 | override_cred = prepare_creds(); | ||
211 | if (!override_cred) | ||
212 | return -ENOMEM; | ||
213 | |||
214 | /* | ||
215 | * CAP_DAC_OVERRIDE for lookup | ||
216 | */ | ||
217 | cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE); | ||
218 | old_cred = override_creds(override_cred); | ||
219 | |||
220 | err = mutex_lock_killable(&dir->d_inode->i_mutex); | ||
221 | if (!err) { | ||
222 | while (rdd->first_maybe_whiteout) { | ||
223 | p = rdd->first_maybe_whiteout; | ||
224 | rdd->first_maybe_whiteout = p->next_maybe_whiteout; | ||
225 | dentry = lookup_one_len(p->name, dir, p->len); | ||
226 | if (!IS_ERR(dentry)) { | ||
227 | p->is_whiteout = ovl_is_whiteout(dentry); | ||
228 | dput(dentry); | ||
229 | } | ||
230 | } | ||
231 | mutex_unlock(&dir->d_inode->i_mutex); | ||
232 | } | ||
233 | revert_creds(old_cred); | ||
234 | put_cred(override_cred); | ||
235 | |||
236 | return err; | ||
237 | } | ||
238 | |||
222 | static inline int ovl_dir_read(struct path *realpath, | 239 | static inline int ovl_dir_read(struct path *realpath, |
223 | struct ovl_readdir_data *rdd) | 240 | struct ovl_readdir_data *rdd) |
224 | { | 241 | { |
@@ -229,7 +246,7 @@ static inline int ovl_dir_read(struct path *realpath, | |||
229 | if (IS_ERR(realfile)) | 246 | if (IS_ERR(realfile)) |
230 | return PTR_ERR(realfile); | 247 | return PTR_ERR(realfile); |
231 | 248 | ||
232 | rdd->dir = realpath->dentry; | 249 | rdd->first_maybe_whiteout = NULL; |
233 | rdd->ctx.pos = 0; | 250 | rdd->ctx.pos = 0; |
234 | do { | 251 | do { |
235 | rdd->count = 0; | 252 | rdd->count = 0; |
@@ -238,6 +255,10 @@ static inline int ovl_dir_read(struct path *realpath, | |||
238 | if (err >= 0) | 255 | if (err >= 0) |
239 | err = rdd->err; | 256 | err = rdd->err; |
240 | } while (!err && rdd->count); | 257 | } while (!err && rdd->count); |
258 | |||
259 | if (!err && rdd->first_maybe_whiteout) | ||
260 | err = ovl_check_whiteouts(realpath->dentry, rdd); | ||
261 | |||
241 | fput(realfile); | 262 | fput(realfile); |
242 | 263 | ||
243 | return err; | 264 | return err; |
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index bf8537c7f455..8a08c582bc22 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c | |||
@@ -273,10 +273,57 @@ static void ovl_dentry_release(struct dentry *dentry) | |||
273 | } | 273 | } |
274 | } | 274 | } |
275 | 275 | ||
276 | static int ovl_dentry_revalidate(struct dentry *dentry, unsigned int flags) | ||
277 | { | ||
278 | struct ovl_entry *oe = dentry->d_fsdata; | ||
279 | unsigned int i; | ||
280 | int ret = 1; | ||
281 | |||
282 | for (i = 0; i < oe->numlower; i++) { | ||
283 | struct dentry *d = oe->lowerstack[i].dentry; | ||
284 | |||
285 | if (d->d_flags & DCACHE_OP_REVALIDATE) { | ||
286 | ret = d->d_op->d_revalidate(d, flags); | ||
287 | if (ret < 0) | ||
288 | return ret; | ||
289 | if (!ret) { | ||
290 | if (!(flags & LOOKUP_RCU)) | ||
291 | d_invalidate(d); | ||
292 | return -ESTALE; | ||
293 | } | ||
294 | } | ||
295 | } | ||
296 | return 1; | ||
297 | } | ||
298 | |||
299 | static int ovl_dentry_weak_revalidate(struct dentry *dentry, unsigned int flags) | ||
300 | { | ||
301 | struct ovl_entry *oe = dentry->d_fsdata; | ||
302 | unsigned int i; | ||
303 | int ret = 1; | ||
304 | |||
305 | for (i = 0; i < oe->numlower; i++) { | ||
306 | struct dentry *d = oe->lowerstack[i].dentry; | ||
307 | |||
308 | if (d->d_flags & DCACHE_OP_WEAK_REVALIDATE) { | ||
309 | ret = d->d_op->d_weak_revalidate(d, flags); | ||
310 | if (ret <= 0) | ||
311 | break; | ||
312 | } | ||
313 | } | ||
314 | return ret; | ||
315 | } | ||
316 | |||
276 | static const struct dentry_operations ovl_dentry_operations = { | 317 | static const struct dentry_operations ovl_dentry_operations = { |
277 | .d_release = ovl_dentry_release, | 318 | .d_release = ovl_dentry_release, |
278 | }; | 319 | }; |
279 | 320 | ||
321 | static const struct dentry_operations ovl_reval_dentry_operations = { | ||
322 | .d_release = ovl_dentry_release, | ||
323 | .d_revalidate = ovl_dentry_revalidate, | ||
324 | .d_weak_revalidate = ovl_dentry_weak_revalidate, | ||
325 | }; | ||
326 | |||
280 | static struct ovl_entry *ovl_alloc_entry(unsigned int numlower) | 327 | static struct ovl_entry *ovl_alloc_entry(unsigned int numlower) |
281 | { | 328 | { |
282 | size_t size = offsetof(struct ovl_entry, lowerstack[numlower]); | 329 | size_t size = offsetof(struct ovl_entry, lowerstack[numlower]); |
@@ -288,6 +335,20 @@ static struct ovl_entry *ovl_alloc_entry(unsigned int numlower) | |||
288 | return oe; | 335 | return oe; |
289 | } | 336 | } |
290 | 337 | ||
338 | static bool ovl_dentry_remote(struct dentry *dentry) | ||
339 | { | ||
340 | return dentry->d_flags & | ||
341 | (DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE); | ||
342 | } | ||
343 | |||
344 | static bool ovl_dentry_weird(struct dentry *dentry) | ||
345 | { | ||
346 | return dentry->d_flags & (DCACHE_NEED_AUTOMOUNT | | ||
347 | DCACHE_MANAGE_TRANSIT | | ||
348 | DCACHE_OP_HASH | | ||
349 | DCACHE_OP_COMPARE); | ||
350 | } | ||
351 | |||
291 | static inline struct dentry *ovl_lookup_real(struct dentry *dir, | 352 | static inline struct dentry *ovl_lookup_real(struct dentry *dir, |
292 | struct qstr *name) | 353 | struct qstr *name) |
293 | { | 354 | { |
@@ -303,6 +364,10 @@ static inline struct dentry *ovl_lookup_real(struct dentry *dir, | |||
303 | } else if (!dentry->d_inode) { | 364 | } else if (!dentry->d_inode) { |
304 | dput(dentry); | 365 | dput(dentry); |
305 | dentry = NULL; | 366 | dentry = NULL; |
367 | } else if (ovl_dentry_weird(dentry)) { | ||
368 | dput(dentry); | ||
369 | /* Don't support traversing automounts and other weirdness */ | ||
370 | dentry = ERR_PTR(-EREMOTE); | ||
306 | } | 371 | } |
307 | return dentry; | 372 | return dentry; |
308 | } | 373 | } |
@@ -350,6 +415,11 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, | |||
350 | goto out; | 415 | goto out; |
351 | 416 | ||
352 | if (this) { | 417 | if (this) { |
418 | if (unlikely(ovl_dentry_remote(this))) { | ||
419 | dput(this); | ||
420 | err = -EREMOTE; | ||
421 | goto out; | ||
422 | } | ||
353 | if (ovl_is_whiteout(this)) { | 423 | if (ovl_is_whiteout(this)) { |
354 | dput(this); | 424 | dput(this); |
355 | this = NULL; | 425 | this = NULL; |
@@ -694,25 +764,6 @@ static void ovl_unescape(char *s) | |||
694 | } | 764 | } |
695 | } | 765 | } |
696 | 766 | ||
697 | static bool ovl_is_allowed_fs_type(struct dentry *root) | ||
698 | { | ||
699 | const struct dentry_operations *dop = root->d_op; | ||
700 | |||
701 | /* | ||
702 | * We don't support: | ||
703 | * - automount filesystems | ||
704 | * - filesystems with revalidate (FIXME for lower layer) | ||
705 | * - filesystems with case insensitive names | ||
706 | */ | ||
707 | if (dop && | ||
708 | (dop->d_manage || dop->d_automount || | ||
709 | dop->d_revalidate || dop->d_weak_revalidate || | ||
710 | dop->d_compare || dop->d_hash)) { | ||
711 | return false; | ||
712 | } | ||
713 | return true; | ||
714 | } | ||
715 | |||
716 | static int ovl_mount_dir_noesc(const char *name, struct path *path) | 767 | static int ovl_mount_dir_noesc(const char *name, struct path *path) |
717 | { | 768 | { |
718 | int err = -EINVAL; | 769 | int err = -EINVAL; |
@@ -727,7 +778,7 @@ static int ovl_mount_dir_noesc(const char *name, struct path *path) | |||
727 | goto out; | 778 | goto out; |
728 | } | 779 | } |
729 | err = -EINVAL; | 780 | err = -EINVAL; |
730 | if (!ovl_is_allowed_fs_type(path->dentry)) { | 781 | if (ovl_dentry_weird(path->dentry)) { |
731 | pr_err("overlayfs: filesystem on '%s' not supported\n", name); | 782 | pr_err("overlayfs: filesystem on '%s' not supported\n", name); |
732 | goto out_put; | 783 | goto out_put; |
733 | } | 784 | } |
@@ -751,13 +802,21 @@ static int ovl_mount_dir(const char *name, struct path *path) | |||
751 | if (tmp) { | 802 | if (tmp) { |
752 | ovl_unescape(tmp); | 803 | ovl_unescape(tmp); |
753 | err = ovl_mount_dir_noesc(tmp, path); | 804 | err = ovl_mount_dir_noesc(tmp, path); |
805 | |||
806 | if (!err) | ||
807 | if (ovl_dentry_remote(path->dentry)) { | ||
808 | pr_err("overlayfs: filesystem on '%s' not supported as upperdir\n", | ||
809 | tmp); | ||
810 | path_put(path); | ||
811 | err = -EINVAL; | ||
812 | } | ||
754 | kfree(tmp); | 813 | kfree(tmp); |
755 | } | 814 | } |
756 | return err; | 815 | return err; |
757 | } | 816 | } |
758 | 817 | ||
759 | static int ovl_lower_dir(const char *name, struct path *path, long *namelen, | 818 | static int ovl_lower_dir(const char *name, struct path *path, long *namelen, |
760 | int *stack_depth) | 819 | int *stack_depth, bool *remote) |
761 | { | 820 | { |
762 | int err; | 821 | int err; |
763 | struct kstatfs statfs; | 822 | struct kstatfs statfs; |
@@ -774,6 +833,9 @@ static int ovl_lower_dir(const char *name, struct path *path, long *namelen, | |||
774 | *namelen = max(*namelen, statfs.f_namelen); | 833 | *namelen = max(*namelen, statfs.f_namelen); |
775 | *stack_depth = max(*stack_depth, path->mnt->mnt_sb->s_stack_depth); | 834 | *stack_depth = max(*stack_depth, path->mnt->mnt_sb->s_stack_depth); |
776 | 835 | ||
836 | if (ovl_dentry_remote(path->dentry)) | ||
837 | *remote = true; | ||
838 | |||
777 | return 0; | 839 | return 0; |
778 | 840 | ||
779 | out_put: | 841 | out_put: |
@@ -827,6 +889,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) | |||
827 | unsigned int numlower; | 889 | unsigned int numlower; |
828 | unsigned int stacklen = 0; | 890 | unsigned int stacklen = 0; |
829 | unsigned int i; | 891 | unsigned int i; |
892 | bool remote = false; | ||
830 | int err; | 893 | int err; |
831 | 894 | ||
832 | err = -ENOMEM; | 895 | err = -ENOMEM; |
@@ -900,7 +963,8 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) | |||
900 | lower = lowertmp; | 963 | lower = lowertmp; |
901 | for (numlower = 0; numlower < stacklen; numlower++) { | 964 | for (numlower = 0; numlower < stacklen; numlower++) { |
902 | err = ovl_lower_dir(lower, &stack[numlower], | 965 | err = ovl_lower_dir(lower, &stack[numlower], |
903 | &ufs->lower_namelen, &sb->s_stack_depth); | 966 | &ufs->lower_namelen, &sb->s_stack_depth, |
967 | &remote); | ||
904 | if (err) | 968 | if (err) |
905 | goto out_put_lowerpath; | 969 | goto out_put_lowerpath; |
906 | 970 | ||
@@ -958,7 +1022,10 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) | |||
958 | if (!ufs->upper_mnt) | 1022 | if (!ufs->upper_mnt) |
959 | sb->s_flags |= MS_RDONLY; | 1023 | sb->s_flags |= MS_RDONLY; |
960 | 1024 | ||
961 | sb->s_d_op = &ovl_dentry_operations; | 1025 | if (remote) |
1026 | sb->s_d_op = &ovl_reval_dentry_operations; | ||
1027 | else | ||
1028 | sb->s_d_op = &ovl_dentry_operations; | ||
962 | 1029 | ||
963 | err = -ENOMEM; | 1030 | err = -ENOMEM; |
964 | oe = ovl_alloc_entry(numlower); | 1031 | oe = ovl_alloc_entry(numlower); |