overlayfs update for 5.2
-----BEGIN PGP SIGNATURE----- iHUEABYIAB0WIQSQHSd0lITzzeNWNm3h3BK/laaZPAUCXNpu6gAKCRDh3BK/laaZ PNYnAQCLMJBZp9AVKU+5onOGKLmgUfnbKZhWJYICW6DVKobo6AEA4aXBIk5TIDiu +a3Ny0nAutdpHcRkbi8jJty91BeJgQg= =iLSD -----END PGP SIGNATURE----- Merge tag 'ovl-update-5.2' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs Pull overlayfs update from Miklos Szeredi: "Just bug fixes in this small update" * tag 'ovl-update-5.2' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs: ovl: relax WARN_ON() for overlapping layers use case ovl: check the capability before cred overridden ovl: do not generate duplicate fsnotify events for "fake" path ovl: support stacked SEEK_HOLE/SEEK_DATA ovl: fix missing upper fs freeze protection on copy up for ioctl
This commit is contained in:
commit
7e9890a350
|
@ -909,14 +909,14 @@ static bool ovl_open_need_copy_up(struct dentry *dentry, int flags)
|
|||
return true;
|
||||
}
|
||||
|
||||
int ovl_open_maybe_copy_up(struct dentry *dentry, unsigned int file_flags)
|
||||
int ovl_maybe_copy_up(struct dentry *dentry, int flags)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if (ovl_open_need_copy_up(dentry, file_flags)) {
|
||||
if (ovl_open_need_copy_up(dentry, flags)) {
|
||||
err = ovl_want_write(dentry);
|
||||
if (!err) {
|
||||
err = ovl_copy_up_flags(dentry, file_flags);
|
||||
err = ovl_copy_up_flags(dentry, flags);
|
||||
ovl_drop_write(dentry);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -260,7 +260,7 @@ static int ovl_instantiate(struct dentry *dentry, struct inode *inode,
|
|||
* hashed directory inode aliases.
|
||||
*/
|
||||
inode = ovl_get_inode(dentry->d_sb, &oip);
|
||||
if (WARN_ON(IS_ERR(inode)))
|
||||
if (IS_ERR(inode))
|
||||
return PTR_ERR(inode);
|
||||
} else {
|
||||
WARN_ON(ovl_inode_real(inode) != d_inode(newdentry));
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <linux/mount.h>
|
||||
#include <linux/xattr.h>
|
||||
#include <linux/uio.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include "overlayfs.h"
|
||||
|
||||
static char ovl_whatisit(struct inode *inode, struct inode *realinode)
|
||||
|
@ -29,10 +30,11 @@ static struct file *ovl_open_realfile(const struct file *file,
|
|||
struct inode *inode = file_inode(file);
|
||||
struct file *realfile;
|
||||
const struct cred *old_cred;
|
||||
int flags = file->f_flags | O_NOATIME | FMODE_NONOTIFY;
|
||||
|
||||
old_cred = ovl_override_creds(inode->i_sb);
|
||||
realfile = open_with_fake_path(&file->f_path, file->f_flags | O_NOATIME,
|
||||
realinode, current_cred());
|
||||
realfile = open_with_fake_path(&file->f_path, flags, realinode,
|
||||
current_cred());
|
||||
revert_creds(old_cred);
|
||||
|
||||
pr_debug("open(%p[%pD2/%c], 0%o) -> (%p, 0%o)\n",
|
||||
|
@ -50,7 +52,7 @@ static int ovl_change_flags(struct file *file, unsigned int flags)
|
|||
int err;
|
||||
|
||||
/* No atime modificaton on underlying */
|
||||
flags |= O_NOATIME;
|
||||
flags |= O_NOATIME | FMODE_NONOTIFY;
|
||||
|
||||
/* If some flag changed that cannot be changed then something's amiss */
|
||||
if (WARN_ON((file->f_flags ^ flags) & ~OVL_SETFL_MASK))
|
||||
|
@ -116,11 +118,10 @@ static int ovl_real_fdget(const struct file *file, struct fd *real)
|
|||
|
||||
static int ovl_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct dentry *dentry = file_dentry(file);
|
||||
struct file *realfile;
|
||||
int err;
|
||||
|
||||
err = ovl_open_maybe_copy_up(dentry, file->f_flags);
|
||||
err = ovl_maybe_copy_up(file_dentry(file), file->f_flags);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -145,11 +146,47 @@ static int ovl_release(struct inode *inode, struct file *file)
|
|||
|
||||
static loff_t ovl_llseek(struct file *file, loff_t offset, int whence)
|
||||
{
|
||||
struct inode *realinode = ovl_inode_real(file_inode(file));
|
||||
struct inode *inode = file_inode(file);
|
||||
struct fd real;
|
||||
const struct cred *old_cred;
|
||||
ssize_t ret;
|
||||
|
||||
return generic_file_llseek_size(file, offset, whence,
|
||||
realinode->i_sb->s_maxbytes,
|
||||
i_size_read(realinode));
|
||||
/*
|
||||
* The two special cases below do not need to involve real fs,
|
||||
* so we can optimizing concurrent callers.
|
||||
*/
|
||||
if (offset == 0) {
|
||||
if (whence == SEEK_CUR)
|
||||
return file->f_pos;
|
||||
|
||||
if (whence == SEEK_SET)
|
||||
return vfs_setpos(file, 0, 0);
|
||||
}
|
||||
|
||||
ret = ovl_real_fdget(file, &real);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Overlay file f_pos is the master copy that is preserved
|
||||
* through copy up and modified on read/write, but only real
|
||||
* fs knows how to SEEK_HOLE/SEEK_DATA and real fs may impose
|
||||
* limitations that are more strict than ->s_maxbytes for specific
|
||||
* files, so we use the real file to perform seeks.
|
||||
*/
|
||||
inode_lock(inode);
|
||||
real.file->f_pos = file->f_pos;
|
||||
|
||||
old_cred = ovl_override_creds(inode->i_sb);
|
||||
ret = vfs_llseek(real.file, offset, whence);
|
||||
revert_creds(old_cred);
|
||||
|
||||
file->f_pos = real.file->f_pos;
|
||||
inode_unlock(inode);
|
||||
|
||||
fdput(real);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ovl_file_accessed(struct file *file)
|
||||
|
@ -372,10 +409,68 @@ static long ovl_real_ioctl(struct file *file, unsigned int cmd,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
static unsigned int ovl_get_inode_flags(struct inode *inode)
|
||||
{
|
||||
unsigned int flags = READ_ONCE(inode->i_flags);
|
||||
unsigned int ovl_iflags = 0;
|
||||
|
||||
if (flags & S_SYNC)
|
||||
ovl_iflags |= FS_SYNC_FL;
|
||||
if (flags & S_APPEND)
|
||||
ovl_iflags |= FS_APPEND_FL;
|
||||
if (flags & S_IMMUTABLE)
|
||||
ovl_iflags |= FS_IMMUTABLE_FL;
|
||||
if (flags & S_NOATIME)
|
||||
ovl_iflags |= FS_NOATIME_FL;
|
||||
|
||||
return ovl_iflags;
|
||||
}
|
||||
|
||||
static long ovl_ioctl_set_flags(struct file *file, unsigned long arg)
|
||||
{
|
||||
long ret;
|
||||
struct inode *inode = file_inode(file);
|
||||
unsigned int flags;
|
||||
unsigned int old_flags;
|
||||
|
||||
if (!inode_owner_or_capable(inode))
|
||||
return -EACCES;
|
||||
|
||||
if (get_user(flags, (int __user *) arg))
|
||||
return -EFAULT;
|
||||
|
||||
ret = mnt_want_write_file(file);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
inode_lock(inode);
|
||||
|
||||
/* Check the capability before cred override */
|
||||
ret = -EPERM;
|
||||
old_flags = ovl_get_inode_flags(inode);
|
||||
if (((flags ^ old_flags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) &&
|
||||
!capable(CAP_LINUX_IMMUTABLE))
|
||||
goto unlock;
|
||||
|
||||
ret = ovl_maybe_copy_up(file_dentry(file), O_WRONLY);
|
||||
if (ret)
|
||||
goto unlock;
|
||||
|
||||
ret = ovl_real_ioctl(file, FS_IOC_SETFLAGS, arg);
|
||||
|
||||
ovl_copyflags(ovl_inode_real(inode), inode);
|
||||
unlock:
|
||||
inode_unlock(inode);
|
||||
|
||||
mnt_drop_write_file(file);
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
long ret;
|
||||
|
||||
switch (cmd) {
|
||||
case FS_IOC_GETFLAGS:
|
||||
|
@ -383,23 +478,7 @@ static long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|||
break;
|
||||
|
||||
case FS_IOC_SETFLAGS:
|
||||
if (!inode_owner_or_capable(inode))
|
||||
return -EACCES;
|
||||
|
||||
ret = mnt_want_write_file(file);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ovl_copy_up_with_data(file_dentry(file));
|
||||
if (!ret) {
|
||||
ret = ovl_real_ioctl(file, cmd, arg);
|
||||
|
||||
inode_lock(inode);
|
||||
ovl_copyflags(ovl_inode_real(inode), inode);
|
||||
inode_unlock(inode);
|
||||
}
|
||||
|
||||
mnt_drop_write_file(file);
|
||||
ret = ovl_ioctl_set_flags(file, arg);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -832,7 +832,7 @@ struct inode *ovl_get_inode(struct super_block *sb,
|
|||
int fsid = bylower ? oip->lowerpath->layer->fsid : 0;
|
||||
bool is_dir, metacopy = false;
|
||||
unsigned long ino = 0;
|
||||
int err = -ENOMEM;
|
||||
int err = oip->newinode ? -EEXIST : -ENOMEM;
|
||||
|
||||
if (!realinode)
|
||||
realinode = d_inode(lowerdentry);
|
||||
|
@ -917,6 +917,7 @@ struct inode *ovl_get_inode(struct super_block *sb,
|
|||
return inode;
|
||||
|
||||
out_err:
|
||||
pr_warn_ratelimited("overlayfs: failed to get inode (%i)\n", err);
|
||||
inode = ERR_PTR(err);
|
||||
goto out;
|
||||
}
|
||||
|
|
|
@ -421,7 +421,7 @@ extern const struct file_operations ovl_file_operations;
|
|||
int ovl_copy_up(struct dentry *dentry);
|
||||
int ovl_copy_up_with_data(struct dentry *dentry);
|
||||
int ovl_copy_up_flags(struct dentry *dentry, int flags);
|
||||
int ovl_open_maybe_copy_up(struct dentry *dentry, unsigned int file_flags);
|
||||
int ovl_maybe_copy_up(struct dentry *dentry, int flags);
|
||||
int ovl_copy_xattr(struct dentry *old, struct dentry *new);
|
||||
int ovl_set_attr(struct dentry *upper, struct kstat *stat);
|
||||
struct ovl_fh *ovl_encode_real_fh(struct dentry *real, bool is_upper);
|
||||
|
|
Loading…
Reference in New Issue