mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-02 23:27:06 +00:00
ovl: Open file with data except for the case of fsync
ovl_open() should open file which contains data and not open metacopy inode. With the introduction of metacopy inodes, with current implementaion we will end up opening metacopy inode as well. But there can be certain circumstances like ovl_fsync() where we want to allow opening a metacopy inode instead. Hence, change ovl_open_realfile() and and add extra parameter which specifies whether to allow opening metacopy inode or not. If this parameter is false, we look for data inode and open that. This should allow covering both the cases. Signed-off-by: Vivek Goyal <vgoyal@redhat.com> Reviewed-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
This commit is contained in:
parent
4823d49c26
commit
8c444d2a97
1 changed files with 30 additions and 9 deletions
|
@ -13,11 +13,20 @@
|
||||||
#include <linux/uio.h>
|
#include <linux/uio.h>
|
||||||
#include "overlayfs.h"
|
#include "overlayfs.h"
|
||||||
|
|
||||||
static struct file *ovl_open_realfile(const struct file *file)
|
static char ovl_whatisit(struct inode *inode, struct inode *realinode)
|
||||||
|
{
|
||||||
|
if (realinode != ovl_inode_upper(inode))
|
||||||
|
return 'l';
|
||||||
|
if (ovl_has_upperdata(inode))
|
||||||
|
return 'u';
|
||||||
|
else
|
||||||
|
return 'm';
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct file *ovl_open_realfile(const struct file *file,
|
||||||
|
struct inode *realinode)
|
||||||
{
|
{
|
||||||
struct inode *inode = file_inode(file);
|
struct inode *inode = file_inode(file);
|
||||||
struct inode *upperinode = ovl_inode_upper(inode);
|
|
||||||
struct inode *realinode = upperinode ?: ovl_inode_lower(inode);
|
|
||||||
struct file *realfile;
|
struct file *realfile;
|
||||||
const struct cred *old_cred;
|
const struct cred *old_cred;
|
||||||
|
|
||||||
|
@ -27,7 +36,7 @@ static struct file *ovl_open_realfile(const struct file *file)
|
||||||
revert_creds(old_cred);
|
revert_creds(old_cred);
|
||||||
|
|
||||||
pr_debug("open(%p[%pD2/%c], 0%o) -> (%p, 0%o)\n",
|
pr_debug("open(%p[%pD2/%c], 0%o) -> (%p, 0%o)\n",
|
||||||
file, file, upperinode ? 'u' : 'l', file->f_flags,
|
file, file, ovl_whatisit(inode, realinode), file->f_flags,
|
||||||
realfile, IS_ERR(realfile) ? 0 : realfile->f_flags);
|
realfile, IS_ERR(realfile) ? 0 : realfile->f_flags);
|
||||||
|
|
||||||
return realfile;
|
return realfile;
|
||||||
|
@ -71,17 +80,24 @@ static int ovl_change_flags(struct file *file, unsigned int flags)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ovl_real_fdget(const struct file *file, struct fd *real)
|
static int ovl_real_fdget_meta(const struct file *file, struct fd *real,
|
||||||
|
bool allow_meta)
|
||||||
{
|
{
|
||||||
struct inode *inode = file_inode(file);
|
struct inode *inode = file_inode(file);
|
||||||
|
struct inode *realinode;
|
||||||
|
|
||||||
real->flags = 0;
|
real->flags = 0;
|
||||||
real->file = file->private_data;
|
real->file = file->private_data;
|
||||||
|
|
||||||
|
if (allow_meta)
|
||||||
|
realinode = ovl_inode_real(inode);
|
||||||
|
else
|
||||||
|
realinode = ovl_inode_realdata(inode);
|
||||||
|
|
||||||
/* Has it been copied up since we'd opened it? */
|
/* Has it been copied up since we'd opened it? */
|
||||||
if (unlikely(file_inode(real->file) != ovl_inode_real(inode))) {
|
if (unlikely(file_inode(real->file) != realinode)) {
|
||||||
real->flags = FDPUT_FPUT;
|
real->flags = FDPUT_FPUT;
|
||||||
real->file = ovl_open_realfile(file);
|
real->file = ovl_open_realfile(file, realinode);
|
||||||
|
|
||||||
return PTR_ERR_OR_ZERO(real->file);
|
return PTR_ERR_OR_ZERO(real->file);
|
||||||
}
|
}
|
||||||
|
@ -93,6 +109,11 @@ static int ovl_real_fdget(const struct file *file, struct fd *real)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ovl_real_fdget(const struct file *file, struct fd *real)
|
||||||
|
{
|
||||||
|
return ovl_real_fdget_meta(file, real, false);
|
||||||
|
}
|
||||||
|
|
||||||
static int ovl_open(struct inode *inode, struct file *file)
|
static int ovl_open(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
struct dentry *dentry = file_dentry(file);
|
struct dentry *dentry = file_dentry(file);
|
||||||
|
@ -106,7 +127,7 @@ static int ovl_open(struct inode *inode, struct file *file)
|
||||||
/* No longer need these flags, so don't pass them on to underlying fs */
|
/* No longer need these flags, so don't pass them on to underlying fs */
|
||||||
file->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
|
file->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
|
||||||
|
|
||||||
realfile = ovl_open_realfile(file);
|
realfile = ovl_open_realfile(file, ovl_inode_realdata(inode));
|
||||||
if (IS_ERR(realfile))
|
if (IS_ERR(realfile))
|
||||||
return PTR_ERR(realfile);
|
return PTR_ERR(realfile);
|
||||||
|
|
||||||
|
@ -243,7 +264,7 @@ static int ovl_fsync(struct file *file, loff_t start, loff_t end, int datasync)
|
||||||
const struct cred *old_cred;
|
const struct cred *old_cred;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = ovl_real_fdget(file, &real);
|
ret = ovl_real_fdget_meta(file, &real, !datasync);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue