summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@redhat.com>2016-12-16 11:02:55 +0100
committerMiklos Szeredi <mszeredi@redhat.com>2016-12-16 11:02:55 +0100
commitca4c8a3a800039c2681d609c5b7491c1bd17c0a7 (patch)
tree9175862945696937768703f572078b5043bd0628
parent6c02cb59e6fe1dfbe4352dbf089e7a16ef6bfac6 (diff)
downloadlinux-ca4c8a3a800039c2681d609c5b7491c1bd17c0a7.tar.bz2
ovl: treat special files like a regular fs
No sense in opening special files on the underlying layers, they work just as well if opened on the overlay. Side effect is that it's no longer possible to connect one side of a pipe opened on overlayfs with the other side opened on the underlying layer. Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
-rw-r--r--fs/overlayfs/dir.c2
-rw-r--r--fs/overlayfs/inode.c24
-rw-r--r--fs/overlayfs/overlayfs.h2
-rw-r--r--fs/overlayfs/super.c7
4 files changed, 16 insertions, 19 deletions
diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
index 617b616ab03b..4ef0d539b097 100644
--- a/fs/overlayfs/dir.c
+++ b/fs/overlayfs/dir.c
@@ -537,7 +537,7 @@ static int ovl_create_object(struct dentry *dentry, int mode, dev_t rdev,
goto out;
err = -ENOMEM;
- inode = ovl_new_inode(dentry->d_sb, mode);
+ inode = ovl_new_inode(dentry->d_sb, mode, rdev);
if (!inode)
goto out_drop_write;
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
index a572e38349f6..a10e948d24fa 100644
--- a/fs/overlayfs/inode.c
+++ b/fs/overlayfs/inode.c
@@ -333,7 +333,7 @@ static const struct inode_operations ovl_symlink_inode_operations = {
.update_time = ovl_update_time,
};
-static void ovl_fill_inode(struct inode *inode, umode_t mode)
+static void ovl_fill_inode(struct inode *inode, umode_t mode, dev_t rdev)
{
inode->i_ino = get_next_ino();
inode->i_mode = mode;
@@ -342,8 +342,11 @@ static void ovl_fill_inode(struct inode *inode, umode_t mode)
inode->i_acl = inode->i_default_acl = ACL_DONT_CACHE;
#endif
- mode &= S_IFMT;
- switch (mode) {
+ switch (mode & S_IFMT) {
+ case S_IFREG:
+ inode->i_op = &ovl_file_inode_operations;
+ break;
+
case S_IFDIR:
inode->i_op = &ovl_dir_inode_operations;
inode->i_fop = &ovl_dir_operations;
@@ -354,26 +357,19 @@ static void ovl_fill_inode(struct inode *inode, umode_t mode)
break;
default:
- WARN(1, "illegal file type: %i\n", mode);
- /* Fall through */
-
- case S_IFREG:
- case S_IFSOCK:
- case S_IFBLK:
- case S_IFCHR:
- case S_IFIFO:
inode->i_op = &ovl_file_inode_operations;
+ init_special_inode(inode, mode, rdev);
break;
}
}
-struct inode *ovl_new_inode(struct super_block *sb, umode_t mode)
+struct inode *ovl_new_inode(struct super_block *sb, umode_t mode, dev_t rdev)
{
struct inode *inode;
inode = new_inode(sb);
if (inode)
- ovl_fill_inode(inode, mode);
+ ovl_fill_inode(inode, mode, rdev);
return inode;
}
@@ -397,7 +393,7 @@ struct inode *ovl_get_inode(struct super_block *sb, struct inode *realinode)
inode = iget5_locked(sb, (unsigned long) realinode,
ovl_inode_test, ovl_inode_set, realinode);
if (inode && inode->i_state & I_NEW) {
- ovl_fill_inode(inode, realinode->i_mode);
+ ovl_fill_inode(inode, realinode->i_mode, realinode->i_rdev);
set_nlink(inode, realinode->i_nlink);
unlock_new_inode(inode);
}
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
index e218e741cb99..95d0d86c2d54 100644
--- a/fs/overlayfs/overlayfs.h
+++ b/fs/overlayfs/overlayfs.h
@@ -195,7 +195,7 @@ int ovl_open_maybe_copy_up(struct dentry *dentry, unsigned int file_flags);
int ovl_update_time(struct inode *inode, struct timespec *ts, int flags);
bool ovl_is_private_xattr(const char *name);
-struct inode *ovl_new_inode(struct super_block *sb, umode_t mode);
+struct inode *ovl_new_inode(struct super_block *sb, umode_t mode, dev_t rdev);
struct inode *ovl_get_inode(struct super_block *sb, struct inode *realinode);
static inline void ovl_copyattr(struct inode *from, struct inode *to)
{
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index 0e100856c7b8..e296312005cc 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -304,7 +304,7 @@ static struct dentry *ovl_d_real(struct dentry *dentry,
{
struct dentry *real;
- if (d_is_dir(dentry)) {
+ if (!d_is_reg(dentry)) {
if (!inode || inode == d_inode(dentry))
return dentry;
goto bug;
@@ -575,7 +575,8 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
if (upperdentry && !d_is_dir(upperdentry)) {
inode = ovl_get_inode(dentry->d_sb, realinode);
} else {
- inode = ovl_new_inode(dentry->d_sb, realinode->i_mode);
+ inode = ovl_new_inode(dentry->d_sb, realinode->i_mode,
+ realinode->i_rdev);
if (inode)
ovl_inode_init(inode, realinode, !!upperdentry);
}
@@ -1324,7 +1325,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
sb->s_fs_info = ufs;
sb->s_flags |= MS_POSIXACL | MS_NOREMOTELOCK;
- root_dentry = d_make_root(ovl_new_inode(sb, S_IFDIR));
+ root_dentry = d_make_root(ovl_new_inode(sb, S_IFDIR, 0));
if (!root_dentry)
goto out_free_oe;