Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1363425 > unrolled thread
| Started by | Miklos Szeredi <miklos@szeredi.hu> |
|---|---|
| First post | 2016-03-23 14:40 +0100 |
| Last post | 2016-03-23 15:30 +0100 |
| Articles | 4 — 2 participants |
Back to article view | Back to linux.kernel
[PATCH v2] fs: add file_dentry() Miklos Szeredi <miklos@szeredi.hu> - 2016-03-23 14:40 +0100
Re: [PATCH v2] fs: add file_dentry() William Dauchy <wdauchy@gmail.com> - 2016-03-23 15:10 +0100
Re: [PATCH v2] fs: add file_dentry() Miklos Szeredi <miklos@szeredi.hu> - 2016-03-23 15:20 +0100
Re: [PATCH v2] fs: add file_dentry() William Dauchy <wdauchy@gmail.com> - 2016-03-23 15:30 +0100
| From | Miklos Szeredi <miklos@szeredi.hu> |
|---|---|
| Date | 2016-03-23 14:40 +0100 |
| Subject | [PATCH v2] fs: add file_dentry() |
| Message-ID | <rfRaW-42Z-19@gated-at.bofh.it> |
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
Cc: David Howells <dhowells@redhat.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Theodore Ts'o <tytso@mit.edu>
Cc: Daniel Axtens <dja@axtens.net>
---
changes in v2:
- rename method to d_op->d_real()
- check d_flag instead of comparing inode for base dentry
- ovl_d_real() now handles recursion
- WARN instead of BUG and be more verbose
- add d_real() helper too
fs/dcache.c | 5 ++++-
fs/overlayfs/super.c | 33 +++++++++++++++++++++++++++++++++
include/linux/dcache.h | 10 ++++++++++
include/linux/fs.h | 10 ++++++++++
4 files changed, 57 insertions(+), 1 deletion(-)
--- 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);
[toc] | [next] | [standalone]
| From | William Dauchy <wdauchy@gmail.com> |
|---|---|
| Date | 2016-03-23 15:10 +0100 |
| Message-ID | <rfRDY-4wf-17@gated-at.bofh.it> |
| In reply to | #1363425 |
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?
--
William
[toc] | [prev] | [next] | [standalone]
| From | Miklos Szeredi <miklos@szeredi.hu> |
|---|---|
| Date | 2016-03-23 15:20 +0100 |
| Message-ID | <rfRNE-4A8-29@gated-at.bofh.it> |
| In reply to | #1363443 |
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
[toc] | [prev] | [next] | [standalone]
| From | William Dauchy <wdauchy@gmail.com> |
|---|---|
| Date | 2016-03-23 15:30 +0100 |
| Message-ID | <rfRXj-4FL-1@gated-at.bofh.it> |
| In reply to | #1363454 |
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 -- William
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web