Message ID | 20160323133606.GF11906@tucsk (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Hello Miklos, On Wed, Mar 23, 2016 at 2:36 PM, Miklos Szeredi <miklos@szeredi.hu> wrote: > This series fixes bugs in nfs and ext4 due to 4bacc9c9234c ("overlayfs: > Make f_path always point to the overlay and f_inode to the underlay"). > > Regular files opened on overlayfs will result in the file being opened on > the underlying filesystem, while f_path points to the overlayfs > mount/dentry. > > This confuses filesystems which get the dentry from struct file and assume > it's theirs. > > Add a new helper, file_dentry() [*], to get the filesystem's own dentry > from the file. This checks file->f_path.dentry->d_flags against > DCACHE_OP_REAL, and returns file->f_path.dentry if DCACHE_OP_REAL is not > set (this is the common, non-overlayfs case). > > In the uncommon case it will call into overlayfs's ->d_real() to get the > underlying dentry, matching file_inode(file). > > The reason we need to check against the inode is that if the file is copied > up while being open, d_real() would return the upper dentry, while the open > file comes from the lower dentry. > > [*] If possible, it's better simply to use file_inode() instead. > > Signed-off-by: Miklos Szeredi <mszeredi@redhat.com> > Tested-by: Goldwyn Rodrigues <rgoldwyn@suse.com> > Reviewed-by: Trond Myklebust <trond.myklebust@primarydata.com> > Cc: <stable@vger.kernel.org> # v4.2 4bacc9c9234c ("overlayfs: Make f_path always point to the overlay and f_inode to the underlay"). This commit is from v4.1 if I am not wrong. So the stable tag might be wrong. Am I missing something?
On Wed, Mar 23, 2016 at 3:06 PM, William Dauchy <wdauchy@gmail.com> wrote: > 4bacc9c9234c ("overlayfs: Make f_path always point to the overlay and > f_inode to the underlay"). > This commit is from v4.1 if I am not wrong. So the stable tag might be wrong. > > Am I missing something? Use "--contains", otherwise "git describe" will just say which kernel the patch has been committed to, not which release it appears in. git describe --contains 4bacc9c9234c v4.2-rc1~2^2~27 Thanks, Miklos -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Wed, Mar 23, 2016 at 3:14 PM, Miklos Szeredi <miklos@szeredi.hu> wrote: > Use "--contains", otherwise "git describe" will just say which kernel > the patch has been committed to, not which release it appears in. > > git describe --contains 4bacc9c9234c > v4.2-rc1~2^2~27 Indeed; I saw the patch in v4.1.x stable https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/commit/fs/internal.h?h=linux-4.1.y&id=9abb3b81094857a1e2d7dea5b2a8605e29d8c77d
Hey Miklos, On 03/23/2016 09:36 AM, Miklos Szeredi wrote: > This series fixes bugs in nfs and ext4 due to 4bacc9c9234c ("overlayfs: > Make f_path always point to the overlay and f_inode to the underlay"). Since that commit got backported into older -stable kernel, it would appear that this file_dentry() series is relevant for pre-4.2 kernels as well. However, backporting it seems to be less than trivial. Could you provide a backport for older -stable kernels please? Thanks, Sasha -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
--- a/fs/dcache.c +++ b/fs/dcache.c @@ -1667,7 +1667,8 @@ void d_set_d_op(struct dentry *dentry, c DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE | DCACHE_OP_DELETE | - DCACHE_OP_SELECT_INODE)); + DCACHE_OP_SELECT_INODE | + DCACHE_OP_REAL)); dentry->d_op = op; if (!op) return; @@ -1685,6 +1686,8 @@ void d_set_d_op(struct dentry *dentry, c dentry->d_flags |= DCACHE_OP_PRUNE; if (op->d_select_inode) dentry->d_flags |= DCACHE_OP_SELECT_INODE; + if (op->d_real) + dentry->d_flags |= DCACHE_OP_REAL; } EXPORT_SYMBOL(d_set_d_op); --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -161,6 +161,7 @@ struct dentry_operations { struct vfsmount *(*d_automount)(struct path *); int (*d_manage)(struct dentry *, bool); struct inode *(*d_select_inode)(struct dentry *, unsigned); + struct dentry *(*d_real)(struct dentry *, struct inode *); } ____cacheline_aligned; /* @@ -229,6 +230,7 @@ struct dentry_operations { #define DCACHE_OP_SELECT_INODE 0x02000000 /* Unioned entry: dcache op selects inode */ #define DCACHE_ENCRYPTED_WITH_KEY 0x04000000 /* dir is encrypted with a valid key */ +#define DCACHE_OP_REAL 0x08000000 extern seqlock_t rename_lock; @@ -555,4 +557,12 @@ static inline struct dentry *d_backing_d return upper; } +static inline struct dentry *d_real(struct dentry *dentry) +{ + if (unlikely(dentry->d_flags & DCACHE_OP_REAL)) + return dentry->d_op->d_real(dentry, NULL); + else + return dentry; +} + #endif /* __LINUX_DCACHE_H */ --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -295,6 +295,37 @@ static void ovl_dentry_release(struct de } } +static struct dentry *ovl_d_real(struct dentry *dentry, struct inode *inode) +{ + struct dentry *real; + + if (d_is_dir(dentry)) { + if (!inode || inode == d_inode(dentry)) + return dentry; + goto bug; + } + + real = ovl_dentry_upper(dentry); + if (real && (!inode || inode == d_inode(real))) + return real; + + real = ovl_dentry_lower(dentry); + if (!real) + goto bug; + + if (!inode || inode == d_inode(real)) + return real; + + /* Handle recursion */ + if (real->d_flags & DCACHE_OP_REAL) + return real->d_op->d_real(real, inode); + +bug: + WARN(1, "ovl_d_real(%pd4, %s:%lu\n): real dentry not found\n", dentry, + inode ? inode->i_sb->s_id : "NULL", inode ? inode->i_ino : 0); + return dentry; +} + static int ovl_dentry_revalidate(struct dentry *dentry, unsigned int flags) { struct ovl_entry *oe = dentry->d_fsdata; @@ -339,11 +370,13 @@ static int ovl_dentry_weak_revalidate(st static const struct dentry_operations ovl_dentry_operations = { .d_release = ovl_dentry_release, .d_select_inode = ovl_d_select_inode, + .d_real = ovl_d_real, }; static const struct dentry_operations ovl_reval_dentry_operations = { .d_release = ovl_dentry_release, .d_select_inode = ovl_d_select_inode, + .d_real = ovl_d_real, .d_revalidate = ovl_dentry_revalidate, .d_weak_revalidate = ovl_dentry_weak_revalidate, }; --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1241,6 +1241,16 @@ static inline struct inode *file_inode(c return f->f_inode; } +static inline struct dentry *file_dentry(const struct file *file) +{ + struct dentry *dentry = file->f_path.dentry; + + if (unlikely(dentry->d_flags & DCACHE_OP_REAL)) + return dentry->d_op->d_real(dentry, file_inode(file)); + else + return dentry; +} + static inline int locks_lock_file_wait(struct file *filp, struct file_lock *fl) { return locks_lock_inode_wait(file_inode(filp), fl);