Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

David Howells and committed by
Al Viro
4bacc9c9 f25801ee

+41 -34
+4 -1
fs/dcache.c
··· 1673 1673 DCACHE_OP_COMPARE | 1674 1674 DCACHE_OP_REVALIDATE | 1675 1675 DCACHE_OP_WEAK_REVALIDATE | 1676 - DCACHE_OP_DELETE )); 1676 + DCACHE_OP_DELETE | 1677 + DCACHE_OP_SELECT_INODE)); 1677 1678 dentry->d_op = op; 1678 1679 if (!op) 1679 1680 return; ··· 1690 1689 dentry->d_flags |= DCACHE_OP_DELETE; 1691 1690 if (op->d_prune) 1692 1691 dentry->d_flags |= DCACHE_OP_PRUNE; 1692 + if (op->d_select_inode) 1693 + dentry->d_flags |= DCACHE_OP_SELECT_INODE; 1693 1694 1694 1695 } 1695 1696 EXPORT_SYMBOL(d_set_d_op);
+1
fs/internal.h
··· 107 107 extern long do_handle_open(int mountdirfd, 108 108 struct file_handle __user *ufh, int open_flag); 109 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 113 * inode.c
+26 -23
fs/open.c
··· 678 678 } 679 679 680 680 static int do_dentry_open(struct file *f, 681 + struct inode *inode, 681 682 int (*open)(struct inode *, struct file *), 682 683 const struct cred *cred) 683 684 { 684 685 static const struct file_operations empty_fops = {}; 685 - struct inode *inode; 686 686 int error; 687 687 688 688 f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK | 689 689 FMODE_PREAD | FMODE_PWRITE; 690 690 691 691 path_get(&f->f_path); 692 - inode = f->f_inode = f->f_path.dentry->d_inode; 692 + f->f_inode = inode; 693 693 f->f_mapping = inode->i_mapping; 694 694 695 695 if (unlikely(f->f_flags & O_PATH)) { ··· 793 793 BUG_ON(*opened & FILE_OPENED); /* once it's opened, it's opened */ 794 794 795 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 798 if (!error) 798 799 *opened |= FILE_OPENED; 799 800 ··· 822 821 return 1; 823 822 } 824 823 EXPORT_SYMBOL(finish_no_open); 824 + 825 + /** 826 + * vfs_open - open the file at the given path 827 + * @path: path to open 828 + * @file: newly allocated file with f_flag initialized 829 + * @cred: credentials to use 830 + */ 831 + int vfs_open(const struct path *path, struct file *file, 832 + const struct cred *cred) 833 + { 834 + struct dentry *dentry = path->dentry; 835 + struct inode *inode = dentry->d_inode; 836 + 837 + file->f_path = *path; 838 + if (dentry->d_flags & DCACHE_OP_SELECT_INODE) { 839 + inode = dentry->d_op->d_select_inode(dentry, file->f_flags); 840 + if (IS_ERR(inode)) 841 + return PTR_ERR(inode); 842 + } 843 + 844 + return do_dentry_open(file, inode, NULL, cred); 845 + } 825 846 826 847 struct file *dentry_open(const struct path *path, int flags, 827 848 const struct cred *cred) ··· 875 852 return f; 876 853 } 877 854 EXPORT_SYMBOL(dentry_open); 878 - 879 - /** 880 - * vfs_open - open the file at the given path 881 - * @path: path to open 882 - * @filp: newly allocated file with f_flag initialized 883 - * @cred: credentials to use 884 - */ 885 - int vfs_open(const struct path *path, struct file *filp, 886 - const struct cred *cred) 887 - { 888 - struct inode *inode = path->dentry->d_inode; 889 - 890 - if (inode->i_op->dentry_open) 891 - return inode->i_op->dentry_open(path->dentry, filp, cred); 892 - else { 893 - filp->f_path = *path; 894 - return do_dentry_open(filp, NULL, cred); 895 - } 896 - } 897 - EXPORT_SYMBOL(vfs_open); 898 855 899 856 static inline int build_open_flags(int flags, umode_t mode, struct open_flags *op) 900 857 {
+6 -8
fs/overlayfs/inode.c
··· 337 337 return true; 338 338 } 339 339 340 - static int ovl_dentry_open(struct dentry *dentry, struct file *file, 341 - const struct cred *cred) 340 + struct inode *ovl_d_select_inode(struct dentry *dentry, unsigned file_flags) 342 341 { 343 342 int err; 344 343 struct path realpath; 345 344 enum ovl_path_type type; 346 345 347 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 348 err = ovl_want_write(dentry); 350 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 353 err = ovl_copy_up_last(dentry, NULL, true); 355 354 else 356 355 err = ovl_copy_up(dentry); 357 356 ovl_drop_write(dentry); 358 357 if (err) 359 - return err; 358 + return ERR_PTR(err); 360 359 361 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 366 static const struct inode_operations ovl_file_inode_operations = { ··· 371 372 .getxattr = ovl_getxattr, 372 373 .listxattr = ovl_listxattr, 373 374 .removexattr = ovl_removexattr, 374 - .dentry_open = ovl_dentry_open, 375 375 }; 376 376 377 377 static const struct inode_operations ovl_symlink_inode_operations = {
+1
fs/overlayfs/overlayfs.h
··· 173 173 void *value, size_t size); 174 174 ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size); 175 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 178 struct inode *ovl_new_inode(struct super_block *sb, umode_t mode, 178 179 struct ovl_entry *oe);
+1
fs/overlayfs/super.c
··· 275 275 276 276 static const struct dentry_operations ovl_dentry_operations = { 277 277 .d_release = ovl_dentry_release, 278 + .d_select_inode = ovl_d_select_inode, 278 279 }; 279 280 280 281 static struct ovl_entry *ovl_alloc_entry(unsigned int numlower)
+2
include/linux/dcache.h
··· 160 160 char *(*d_dname)(struct dentry *, char *, int); 161 161 struct vfsmount *(*d_automount)(struct path *); 162 162 int (*d_manage)(struct dentry *, bool); 163 + struct inode *(*d_select_inode)(struct dentry *, unsigned); 163 164 } ____cacheline_aligned; 164 165 165 166 /* ··· 226 225 227 226 #define DCACHE_MAY_FREE 0x00800000 228 227 #define DCACHE_FALLTHRU 0x01000000 /* Fall through to lower layer */ 228 + #define DCACHE_OP_SELECT_INODE 0x02000000 /* Unioned entry: dcache op selects inode */ 229 229 230 230 extern seqlock_t rename_lock; 231 231
-2
include/linux/fs.h
··· 1641 1641 int (*set_acl)(struct inode *, struct posix_acl *, int); 1642 1642 1643 1643 /* WARNING: probably going away soon, do not use! */ 1644 - int (*dentry_open)(struct dentry *, struct file *, const struct cred *); 1645 1644 } ____cacheline_aligned; 1646 1645 1647 1646 ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector, ··· 2193 2194 extern struct file *filp_open(const char *, int, umode_t); 2194 2195 extern struct file *file_open_root(struct dentry *, struct vfsmount *, 2195 2196 const char *, int); 2196 - extern int vfs_open(const struct path *, struct file *, const struct cred *); 2197 2197 extern struct file * dentry_open(const struct path *, int, const struct cred *); 2198 2198 extern int filp_close(struct file *, fl_owner_t id); 2199 2199