diff options
author | David Howells <dhowells@redhat.com> | 2015-06-18 09:32:31 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2015-06-19 03:19:32 -0400 |
commit | 4bacc9c9234c7c8eec44f5ed4e960d9f96fa0f01 (patch) | |
tree | 1ecac38332d4e8cf5370627f1214a1d7c5ff7529 | |
parent | f25801ee4680ef1db21e15c112e6e5fe3ffe8da5 (diff) |
overlayfs: Make f_path always point to the overlay and f_inode to the underlay
Make file->f_path always point to the overlay dentry so that the path in
/proc/pid/fd is correct and to ensure that label-based LSMs have access to the
overlay as well as the underlay (path-based LSMs probably don't need it).
Using my union testsuite to set things up, before the patch I see:
[root@andromeda union-testsuite]# bash 5</mnt/a/foo107
[root@andromeda union-testsuite]# ls -l /proc/$$/fd/
...
lr-x------. 1 root root 64 Jun 5 14:38 5 -> /a/foo107
[root@andromeda union-testsuite]# stat /mnt/a/foo107
...
Device: 23h/35d Inode: 13381 Links: 1
...
[root@andromeda union-testsuite]# stat -L /proc/$$/fd/5
...
Device: 23h/35d Inode: 13381 Links: 1
...
After the patch:
[root@andromeda union-testsuite]# bash 5</mnt/a/foo107
[root@andromeda union-testsuite]# ls -l /proc/$$/fd/
...
lr-x------. 1 root root 64 Jun 5 14:22 5 -> /mnt/a/foo107
[root@andromeda union-testsuite]# stat /mnt/a/foo107
...
Device: 23h/35d Inode: 40346 Links: 1
...
[root@andromeda union-testsuite]# stat -L /proc/$$/fd/5
...
Device: 23h/35d Inode: 40346 Links: 1
...
Note the change in where /proc/$$/fd/5 points to in the ls command. It was
pointing to /a/foo107 (which doesn't exist) and now points to /mnt/a/foo107
(which is correct).
The inode accessed, however, is the lower layer. The union layer is on device
25h/37d and the upper layer on 24h/36d.
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | fs/dcache.c | 5 | ||||
-rw-r--r-- | fs/internal.h | 1 | ||||
-rw-r--r-- | fs/open.c | 49 | ||||
-rw-r--r-- | fs/overlayfs/inode.c | 14 | ||||
-rw-r--r-- | fs/overlayfs/overlayfs.h | 1 | ||||
-rw-r--r-- | fs/overlayfs/super.c | 1 | ||||
-rw-r--r-- | include/linux/dcache.h | 2 | ||||
-rw-r--r-- | include/linux/fs.h | 2 |
8 files changed, 41 insertions, 34 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index 37b5afdaf698..c4ce35110704 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -1673,7 +1673,8 @@ void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op) | |||
1673 | DCACHE_OP_COMPARE | | 1673 | DCACHE_OP_COMPARE | |
1674 | DCACHE_OP_REVALIDATE | | 1674 | DCACHE_OP_REVALIDATE | |
1675 | DCACHE_OP_WEAK_REVALIDATE | | 1675 | DCACHE_OP_WEAK_REVALIDATE | |
1676 | DCACHE_OP_DELETE )); | 1676 | DCACHE_OP_DELETE | |
1677 | DCACHE_OP_SELECT_INODE)); | ||
1677 | dentry->d_op = op; | 1678 | dentry->d_op = op; |
1678 | if (!op) | 1679 | if (!op) |
1679 | return; | 1680 | return; |
@@ -1689,6 +1690,8 @@ void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op) | |||
1689 | dentry->d_flags |= DCACHE_OP_DELETE; | 1690 | dentry->d_flags |= DCACHE_OP_DELETE; |
1690 | if (op->d_prune) | 1691 | if (op->d_prune) |
1691 | dentry->d_flags |= DCACHE_OP_PRUNE; | 1692 | dentry->d_flags |= DCACHE_OP_PRUNE; |
1693 | if (op->d_select_inode) | ||
1694 | dentry->d_flags |= DCACHE_OP_SELECT_INODE; | ||
1692 | 1695 | ||
1693 | } | 1696 | } |
1694 | EXPORT_SYMBOL(d_set_d_op); | 1697 | EXPORT_SYMBOL(d_set_d_op); |
diff --git a/fs/internal.h b/fs/internal.h index 01dce1d1476b..4d5af583ab03 100644 --- a/fs/internal.h +++ b/fs/internal.h | |||
@@ -107,6 +107,7 @@ extern struct file *do_file_open_root(struct dentry *, struct vfsmount *, | |||
107 | extern long do_handle_open(int mountdirfd, | 107 | extern long do_handle_open(int mountdirfd, |
108 | struct file_handle __user *ufh, int open_flag); | 108 | struct file_handle __user *ufh, int open_flag); |
109 | extern int open_check_o_direct(struct file *f); | 109 | extern int open_check_o_direct(struct file *f); |
110 | extern int vfs_open(const struct path *, struct file *, const struct cred *); | ||
110 | 111 | ||
111 | /* | 112 | /* |
112 | * inode.c | 113 | * inode.c |
@@ -678,18 +678,18 @@ int open_check_o_direct(struct file *f) | |||
678 | } | 678 | } |
679 | 679 | ||
680 | static int do_dentry_open(struct file *f, | 680 | static int do_dentry_open(struct file *f, |
681 | struct inode *inode, | ||
681 | int (*open)(struct inode *, struct file *), | 682 | int (*open)(struct inode *, struct file *), |
682 | const struct cred *cred) | 683 | const struct cred *cred) |
683 | { | 684 | { |
684 | static const struct file_operations empty_fops = {}; | 685 | static const struct file_operations empty_fops = {}; |
685 | struct inode *inode; | ||
686 | int error; | 686 | int error; |
687 | 687 | ||
688 | f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK | | 688 | f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK | |
689 | FMODE_PREAD | FMODE_PWRITE; | 689 | FMODE_PREAD | FMODE_PWRITE; |
690 | 690 | ||
691 | path_get(&f->f_path); | 691 | path_get(&f->f_path); |
692 | inode = f->f_inode = f->f_path.dentry->d_inode; | 692 | f->f_inode = inode; |
693 | f->f_mapping = inode->i_mapping; | 693 | f->f_mapping = inode->i_mapping; |
694 | 694 | ||
695 | if (unlikely(f->f_flags & O_PATH)) { | 695 | if (unlikely(f->f_flags & O_PATH)) { |
@@ -793,7 +793,8 @@ int finish_open(struct file *file, struct dentry *dentry, | |||
793 | BUG_ON(*opened & FILE_OPENED); /* once it's opened, it's opened */ | 793 | BUG_ON(*opened & FILE_OPENED); /* once it's opened, it's opened */ |
794 | 794 | ||
795 | file->f_path.dentry = dentry; | 795 | file->f_path.dentry = dentry; |
796 | error = do_dentry_open(file, open, current_cred()); | 796 | error = do_dentry_open(file, d_backing_inode(dentry), open, |
797 | current_cred()); | ||
797 | if (!error) | 798 | if (!error) |
798 | *opened |= FILE_OPENED; | 799 | *opened |= FILE_OPENED; |
799 | 800 | ||
@@ -822,6 +823,28 @@ int finish_no_open(struct file *file, struct dentry *dentry) | |||
822 | } | 823 | } |
823 | EXPORT_SYMBOL(finish_no_open); | 824 | EXPORT_SYMBOL(finish_no_open); |
824 | 825 | ||
826 | /** | ||
827 | * vfs_open - open the file at the given path | ||
828 | * @path: path to open | ||
829 | * @file: newly allocated file with f_flag initialized | ||
830 | * @cred: credentials to use | ||
831 | */ | ||
832 | int vfs_open(const struct path *path, struct file *file, | ||
833 | const struct cred *cred) | ||
834 | { | ||
835 | struct dentry *dentry = path->dentry; | ||
836 | struct inode *inode = dentry->d_inode; | ||
837 | |||
838 | file->f_path = *path; | ||
839 | if (dentry->d_flags & DCACHE_OP_SELECT_INODE) { | ||
840 | inode = dentry->d_op->d_select_inode(dentry, file->f_flags); | ||
841 | if (IS_ERR(inode)) | ||
842 | return PTR_ERR(inode); | ||
843 | } | ||
844 | |||
845 | return do_dentry_open(file, inode, NULL, cred); | ||
846 | } | ||
847 | |||
825 | struct file *dentry_open(const struct path *path, int flags, | 848 | struct file *dentry_open(const struct path *path, int flags, |
826 | const struct cred *cred) | 849 | const struct cred *cred) |
827 | { | 850 | { |
@@ -853,26 +876,6 @@ struct file *dentry_open(const struct path *path, int flags, | |||
853 | } | 876 | } |
854 | EXPORT_SYMBOL(dentry_open); | 877 | EXPORT_SYMBOL(dentry_open); |
855 | 878 | ||
856 | /** | ||
857 | * vfs_open - open the file at the given path | ||
858 | * @path: path to open | ||
859 | * @filp: newly allocated file with f_flag initialized | ||
860 | * @cred: credentials to use | ||
861 | */ | ||
862 | int vfs_open(const struct path *path, struct file *filp, | ||
863 | const struct cred *cred) | ||
864 | { | ||
865 | struct inode *inode = path->dentry->d_inode; | ||
866 | |||
867 | if (inode->i_op->dentry_open) | ||
868 | return inode->i_op->dentry_open(path->dentry, filp, cred); | ||
869 | else { | ||
870 | filp->f_path = *path; | ||
871 | return do_dentry_open(filp, NULL, cred); | ||
872 | } | ||
873 | } | ||
874 | EXPORT_SYMBOL(vfs_open); | ||
875 | |||
876 | static inline int build_open_flags(int flags, umode_t mode, struct open_flags *op) | 879 | static inline int build_open_flags(int flags, umode_t mode, struct open_flags *op) |
877 | { | 880 | { |
878 | int lookup_flags = 0; | 881 | int lookup_flags = 0; |
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index 21079d1ca2aa..f140e3dbfb7b 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c | |||
@@ -337,31 +337,30 @@ static bool ovl_open_need_copy_up(int flags, enum ovl_path_type type, | |||
337 | return true; | 337 | return true; |
338 | } | 338 | } |
339 | 339 | ||
340 | static int ovl_dentry_open(struct dentry *dentry, struct file *file, | 340 | struct inode *ovl_d_select_inode(struct dentry *dentry, unsigned file_flags) |
341 | const struct cred *cred) | ||
342 | { | 341 | { |
343 | int err; | 342 | int err; |
344 | struct path realpath; | 343 | struct path realpath; |
345 | enum ovl_path_type type; | 344 | enum ovl_path_type type; |
346 | 345 | ||
347 | type = ovl_path_real(dentry, &realpath); | 346 | type = ovl_path_real(dentry, &realpath); |
348 | if (ovl_open_need_copy_up(file->f_flags, type, realpath.dentry)) { | 347 | if (ovl_open_need_copy_up(file_flags, type, realpath.dentry)) { |
349 | err = ovl_want_write(dentry); | 348 | err = ovl_want_write(dentry); |
350 | if (err) | 349 | if (err) |
351 | return err; | 350 | return ERR_PTR(err); |
352 | 351 | ||
353 | if (file->f_flags & O_TRUNC) | 352 | if (file_flags & O_TRUNC) |
354 | err = ovl_copy_up_last(dentry, NULL, true); | 353 | err = ovl_copy_up_last(dentry, NULL, true); |
355 | else | 354 | else |
356 | err = ovl_copy_up(dentry); | 355 | err = ovl_copy_up(dentry); |
357 | ovl_drop_write(dentry); | 356 | ovl_drop_write(dentry); |
358 | if (err) | 357 | if (err) |
359 | return err; | 358 | return ERR_PTR(err); |
360 | 359 | ||
361 | ovl_path_upper(dentry, &realpath); | 360 | ovl_path_upper(dentry, &realpath); |
362 | } | 361 | } |
363 | 362 | ||
364 | return vfs_open(&realpath, file, cred); | 363 | return d_backing_inode(realpath.dentry); |
365 | } | 364 | } |
366 | 365 | ||
367 | static const struct inode_operations ovl_file_inode_operations = { | 366 | static const struct inode_operations ovl_file_inode_operations = { |
@@ -372,7 +371,6 @@ static const struct inode_operations ovl_file_inode_operations = { | |||
372 | .getxattr = ovl_getxattr, | 371 | .getxattr = ovl_getxattr, |
373 | .listxattr = ovl_listxattr, | 372 | .listxattr = ovl_listxattr, |
374 | .removexattr = ovl_removexattr, | 373 | .removexattr = ovl_removexattr, |
375 | .dentry_open = ovl_dentry_open, | ||
376 | }; | 374 | }; |
377 | 375 | ||
378 | static const struct inode_operations ovl_symlink_inode_operations = { | 376 | static const struct inode_operations ovl_symlink_inode_operations = { |
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index 17ac5afc9ffb..ea5a40b06e3a 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h | |||
@@ -173,6 +173,7 @@ ssize_t ovl_getxattr(struct dentry *dentry, const char *name, | |||
173 | void *value, size_t size); | 173 | void *value, size_t size); |
174 | ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size); | 174 | ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size); |
175 | int ovl_removexattr(struct dentry *dentry, const char *name); | 175 | int ovl_removexattr(struct dentry *dentry, const char *name); |
176 | struct inode *ovl_d_select_inode(struct dentry *dentry, unsigned file_flags); | ||
176 | 177 | ||
177 | struct inode *ovl_new_inode(struct super_block *sb, umode_t mode, | 178 | struct inode *ovl_new_inode(struct super_block *sb, umode_t mode, |
178 | struct ovl_entry *oe); | 179 | struct ovl_entry *oe); |
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index 5f0d1993e6e3..84c5e27fbfd9 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c | |||
@@ -275,6 +275,7 @@ static void ovl_dentry_release(struct dentry *dentry) | |||
275 | 275 | ||
276 | static const struct dentry_operations ovl_dentry_operations = { | 276 | static const struct dentry_operations ovl_dentry_operations = { |
277 | .d_release = ovl_dentry_release, | 277 | .d_release = ovl_dentry_release, |
278 | .d_select_inode = ovl_d_select_inode, | ||
278 | }; | 279 | }; |
279 | 280 | ||
280 | static struct ovl_entry *ovl_alloc_entry(unsigned int numlower) | 281 | static struct ovl_entry *ovl_alloc_entry(unsigned int numlower) |
diff --git a/include/linux/dcache.h b/include/linux/dcache.h index df334cbacc6d..167ec0934049 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h | |||
@@ -160,6 +160,7 @@ struct dentry_operations { | |||
160 | char *(*d_dname)(struct dentry *, char *, int); | 160 | char *(*d_dname)(struct dentry *, char *, int); |
161 | struct vfsmount *(*d_automount)(struct path *); | 161 | struct vfsmount *(*d_automount)(struct path *); |
162 | int (*d_manage)(struct dentry *, bool); | 162 | int (*d_manage)(struct dentry *, bool); |
163 | struct inode *(*d_select_inode)(struct dentry *, unsigned); | ||
163 | } ____cacheline_aligned; | 164 | } ____cacheline_aligned; |
164 | 165 | ||
165 | /* | 166 | /* |
@@ -225,6 +226,7 @@ struct dentry_operations { | |||
225 | 226 | ||
226 | #define DCACHE_MAY_FREE 0x00800000 | 227 | #define DCACHE_MAY_FREE 0x00800000 |
227 | #define DCACHE_FALLTHRU 0x01000000 /* Fall through to lower layer */ | 228 | #define DCACHE_FALLTHRU 0x01000000 /* Fall through to lower layer */ |
229 | #define DCACHE_OP_SELECT_INODE 0x02000000 /* Unioned entry: dcache op selects inode */ | ||
228 | 230 | ||
229 | extern seqlock_t rename_lock; | 231 | extern seqlock_t rename_lock; |
230 | 232 | ||
diff --git a/include/linux/fs.h b/include/linux/fs.h index b577e801b4af..2bd77e10e8e5 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -1641,7 +1641,6 @@ struct inode_operations { | |||
1641 | int (*set_acl)(struct inode *, struct posix_acl *, int); | 1641 | int (*set_acl)(struct inode *, struct posix_acl *, int); |
1642 | 1642 | ||
1643 | /* WARNING: probably going away soon, do not use! */ | 1643 | /* WARNING: probably going away soon, do not use! */ |
1644 | int (*dentry_open)(struct dentry *, struct file *, const struct cred *); | ||
1645 | } ____cacheline_aligned; | 1644 | } ____cacheline_aligned; |
1646 | 1645 | ||
1647 | ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector, | 1646 | ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector, |
@@ -2194,7 +2193,6 @@ extern struct file *file_open_name(struct filename *, int, umode_t); | |||
2194 | extern struct file *filp_open(const char *, int, umode_t); | 2193 | extern struct file *filp_open(const char *, int, umode_t); |
2195 | extern struct file *file_open_root(struct dentry *, struct vfsmount *, | 2194 | extern struct file *file_open_root(struct dentry *, struct vfsmount *, |
2196 | const char *, int); | 2195 | const char *, int); |
2197 | extern int vfs_open(const struct path *, struct file *, const struct cred *); | ||
2198 | extern struct file * dentry_open(const struct path *, int, const struct cred *); | 2196 | extern struct file * dentry_open(const struct path *, int, const struct cred *); |
2199 | extern int filp_close(struct file *, fl_owner_t id); | 2197 | extern int filp_close(struct file *, fl_owner_t id); |
2200 | 2198 | ||