Re: linux-next: manual merge of the y2038 tree with the overlayfs tree

From: Stephen Rothwell
Date: Thu Jun 14 2018 - 22:41:14 EST


Hi all,

This is now a conflict between the overlayfs tree and Linus' tree. (I
restarted my merging after I noticed that Linus merged more stuff.)

On Fri, 15 Jun 2018 10:43:24 +1000 Stephen Rothwell <sfr@xxxxxxxxxxxxxxxx> wrote:
>
> Today's linux-next merge of the y2038 tree got conflicts in:
>
> fs/inode.c
> fs/overlayfs/inode.c
> fs/overlayfs/overlayfs.h
>
> between various commits from the overlayfs tree and commits:
>
> 8efd6894ff08 ("fs: add timespec64_truncate()")
> 95582b008388 ("vfs: change inode times to use struct timespec64")
>
> from the y2038 tree.
>
> I fixed it up (I copied the resolutions that used to be in the merge of
> the overlayfs into the y2038 tree - see below) and can carry the fix as
> necessary. This is now fixed as far as linux-next is concerned, but any
> non trivial conflicts should be mentioned to your upstream maintainer
> when your tree is submitted for merging. You may also want to consider
> cooperating with the maintainer of the conflicting tree to minimise any
> particularly complex conflicts.
>
> --
> Cheers,
> Stephen Rothwell
>
> diff --cc fs/inode.c
> index 9a6fc2f2d220,9fe1f941be02..55373fcba3a5
> --- a/fs/inode.c
> +++ b/fs/inode.c
> @@@ -1635,10 -1681,11 +1635,10 @@@ static int update_time(struct inode *in
> * This function automatically handles read only file systems and media,
> * as well as the "noatime" flag and inode specific "noatime" markers.
> */
> -bool __atime_needs_update(const struct path *path, struct inode *inode,
> - bool rcu)
> +bool atime_needs_update(const struct path *path, struct inode *inode)
> {
> struct vfsmount *mnt = path->mnt;
> - struct timespec now;
> + struct timespec64 now;
>
> if (inode->i_flags & S_NOATIME)
> return false;
> @@@ -1661,10 -1708,10 +1661,10 @@@
>
> now = current_time(inode);
>
> - if (!relatime_need_update(mnt, inode, now))
> - if (!relatime_need_update(path, inode, timespec64_to_timespec(now), rcu))
> ++ if (!relatime_need_update(mnt, inode, timespec64_to_timespec(now)))
> return false;
>
> - if (timespec_equal(&inode->i_atime, &now))
> + if (timespec64_equal(&inode->i_atime, &now))
> return false;
>
> return true;
> @@@ -1674,9 -1721,9 +1674,9 @@@ void touch_atime(const struct path *pat
> {
> struct vfsmount *mnt = path->mnt;
> struct inode *inode = d_inode(path->dentry);
> - struct timespec now;
> + struct timespec64 now;
>
> - if (!__atime_needs_update(path, inode, false))
> + if (!atime_needs_update(path, inode))
> return;
>
> if (!sb_start_write_trylock(inode->i_sb))
> diff --cc fs/overlayfs/file.c
> index f801e1175a0b,000000000000..c6bce11ac6d3
> mode 100644,000000..100644
> --- a/fs/overlayfs/file.c
> +++ b/fs/overlayfs/file.c
> @@@ -1,508 -1,0 +1,508 @@@
> +/*
> + * Copyright (C) 2017 Red Hat, Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License version 2 as published by
> + * the Free Software Foundation.
> + */
> +
> +#include <linux/cred.h>
> +#include <linux/file.h>
> +#include <linux/mount.h>
> +#include <linux/xattr.h>
> +#include <linux/uio.h>
> +#include "overlayfs.h"
> +
> +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 file *realfile;
> + const struct cred *old_cred;
> +
> + old_cred = ovl_override_creds(inode->i_sb);
> + realfile = path_open(&file->f_path, file->f_flags | O_NOATIME,
> + realinode, current_cred(), false);
> + revert_creds(old_cred);
> +
> + pr_debug("open(%p[%pD2/%c], 0%o) -> (%p, 0%o)\n",
> + file, file, ovl_whatisit(inode, realinode), file->f_flags,
> + realfile, IS_ERR(realfile) ? 0 : realfile->f_flags);
> +
> + return realfile;
> +}
> +
> +#define OVL_SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | O_DIRECT)
> +
> +static int ovl_change_flags(struct file *file, unsigned int flags)
> +{
> + struct inode *inode = file_inode(file);
> + int err;
> +
> + /* No atime modificaton on underlying */
> + flags |= O_NOATIME;
> +
> + /* If some flag changed that cannot be changed then something's amiss */
> + if (WARN_ON((file->f_flags ^ flags) & ~OVL_SETFL_MASK))
> + return -EIO;
> +
> + flags &= OVL_SETFL_MASK;
> +
> + if (((flags ^ file->f_flags) & O_APPEND) && IS_APPEND(inode))
> + return -EPERM;
> +
> + if (flags & O_DIRECT) {
> + if (!file->f_mapping->a_ops ||
> + !file->f_mapping->a_ops->direct_IO)
> + return -EINVAL;
> + }
> +
> + if (file->f_op->check_flags) {
> + err = file->f_op->check_flags(flags);
> + if (err)
> + return err;
> + }
> +
> + spin_lock(&file->f_lock);
> + file->f_flags = (file->f_flags & ~OVL_SETFL_MASK) | flags;
> + spin_unlock(&file->f_lock);
> +
> + return 0;
> +}
> +
> +static int ovl_real_fdget_meta(const struct file *file, struct fd *real,
> + bool allow_meta)
> +{
> + struct inode *inode = file_inode(file);
> + struct inode *realinode;
> +
> + real->flags = 0;
> + 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? */
> + if (unlikely(file_inode(real->file) != realinode)) {
> + real->flags = FDPUT_FPUT;
> + real->file = ovl_open_realfile(file, realinode);
> +
> + return PTR_ERR_OR_ZERO(real->file);
> + }
> +
> + /* Did the flags change since open? */
> + if (unlikely((file->f_flags ^ real->file->f_flags) & ~O_NOATIME))
> + return ovl_change_flags(real->file, file->f_flags);
> +
> + 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)
> +{
> + struct dentry *dentry = file_dentry(file);
> + struct file *realfile;
> + int err;
> +
> + err = ovl_open_maybe_copy_up(dentry, file->f_flags);
> + if (err)
> + return err;
> +
> + /* 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);
> +
> + realfile = ovl_open_realfile(file, ovl_inode_realdata(inode));
> + if (IS_ERR(realfile))
> + return PTR_ERR(realfile);
> +
> + /* For O_DIRECT dentry_open() checks f_mapping->a_ops->direct_IO */
> + file->f_mapping = realfile->f_mapping;
> +
> + file->private_data = realfile;
> +
> + return 0;
> +}
> +
> +static int ovl_release(struct inode *inode, struct file *file)
> +{
> + fput(file->private_data);
> +
> + return 0;
> +}
> +
> +static loff_t ovl_llseek(struct file *file, loff_t offset, int whence)
> +{
> + struct inode *realinode = ovl_inode_real(file_inode(file));
> +
> + return generic_file_llseek_size(file, offset, whence,
> + realinode->i_sb->s_maxbytes,
> + i_size_read(realinode));
> +}
> +
> +static void ovl_file_accessed(struct file *file)
> +{
> + struct inode *inode, *upperinode;
> +
> + if (file->f_flags & O_NOATIME)
> + return;
> +
> + inode = file_inode(file);
> + upperinode = ovl_inode_upper(inode);
> +
> + if (!upperinode)
> + return;
> +
> - if ((!timespec_equal(&inode->i_mtime, &upperinode->i_mtime) ||
> - !timespec_equal(&inode->i_ctime, &upperinode->i_ctime))) {
> ++ if ((!timespec64_equal(&inode->i_mtime, &upperinode->i_mtime) ||
> ++ !timespec64_equal(&inode->i_ctime, &upperinode->i_ctime))) {
> + inode->i_mtime = upperinode->i_mtime;
> + inode->i_ctime = upperinode->i_ctime;
> + }
> +
> + touch_atime(&file->f_path);
> +}
> +
> +static rwf_t ovl_iocb_to_rwf(struct kiocb *iocb)
> +{
> + int ifl = iocb->ki_flags;
> + rwf_t flags = 0;
> +
> + if (ifl & IOCB_NOWAIT)
> + flags |= RWF_NOWAIT;
> + if (ifl & IOCB_HIPRI)
> + flags |= RWF_HIPRI;
> + if (ifl & IOCB_DSYNC)
> + flags |= RWF_DSYNC;
> + if (ifl & IOCB_SYNC)
> + flags |= RWF_SYNC;
> +
> + return flags;
> +}
> +
> +static ssize_t ovl_read_iter(struct kiocb *iocb, struct iov_iter *iter)
> +{
> + struct file *file = iocb->ki_filp;
> + struct fd real;
> + const struct cred *old_cred;
> + ssize_t ret;
> +
> + if (!iov_iter_count(iter))
> + return 0;
> +
> + ret = ovl_real_fdget(file, &real);
> + if (ret)
> + return ret;
> +
> + old_cred = ovl_override_creds(file_inode(file)->i_sb);
> + ret = vfs_iter_read(real.file, iter, &iocb->ki_pos,
> + ovl_iocb_to_rwf(iocb));
> + revert_creds(old_cred);
> +
> + ovl_file_accessed(file);
> +
> + fdput(real);
> +
> + return ret;
> +}
> +
> +static ssize_t ovl_write_iter(struct kiocb *iocb, struct iov_iter *iter)
> +{
> + struct file *file = iocb->ki_filp;
> + struct inode *inode = file_inode(file);
> + struct fd real;
> + const struct cred *old_cred;
> + ssize_t ret;
> +
> + if (!iov_iter_count(iter))
> + return 0;
> +
> + inode_lock(inode);
> + /* Update mode */
> + ovl_copyattr(ovl_inode_real(inode), inode);
> + ret = file_remove_privs(file);
> + if (ret)
> + goto out_unlock;
> +
> + ret = ovl_real_fdget(file, &real);
> + if (ret)
> + goto out_unlock;
> +
> + old_cred = ovl_override_creds(file_inode(file)->i_sb);
> + ret = vfs_iter_write(real.file, iter, &iocb->ki_pos,
> + ovl_iocb_to_rwf(iocb));
> + revert_creds(old_cred);
> +
> + /* Update size */
> + ovl_copyattr(ovl_inode_real(inode), inode);
> +
> + fdput(real);
> +
> +out_unlock:
> + inode_unlock(inode);
> +
> + return ret;
> +}
> +
> +static int ovl_fsync(struct file *file, loff_t start, loff_t end, int datasync)
> +{
> + struct fd real;
> + const struct cred *old_cred;
> + int ret;
> +
> + ret = ovl_real_fdget_meta(file, &real, !datasync);
> + if (ret)
> + return ret;
> +
> + /* Don't sync lower file for fear of receiving EROFS error */
> + if (file_inode(real.file) == ovl_inode_upper(file_inode(file))) {
> + old_cred = ovl_override_creds(file_inode(file)->i_sb);
> + ret = vfs_fsync_range(real.file, start, end, datasync);
> + revert_creds(old_cred);
> + }
> +
> + fdput(real);
> +
> + return ret;
> +}
> +
> +static int ovl_mmap(struct file *file, struct vm_area_struct *vma)
> +{
> + struct fd real;
> + const struct cred *old_cred;
> + int ret;
> +
> + ret = ovl_real_fdget(file, &real);
> + if (ret)
> + return ret;
> +
> + /* transfer ref: */
> + fput(vma->vm_file);
> + vma->vm_file = get_file(real.file);
> + fdput(real);
> +
> + if (!vma->vm_file->f_op->mmap)
> + return -ENODEV;
> +
> + old_cred = ovl_override_creds(file_inode(file)->i_sb);
> + ret = call_mmap(vma->vm_file, vma);
> + revert_creds(old_cred);
> +
> + ovl_file_accessed(file);
> +
> + return ret;
> +}
> +
> +static long ovl_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
> +{
> + struct inode *inode = file_inode(file);
> + struct fd real;
> + const struct cred *old_cred;
> + int ret;
> +
> + ret = ovl_real_fdget(file, &real);
> + if (ret)
> + return ret;
> +
> + old_cred = ovl_override_creds(file_inode(file)->i_sb);
> + ret = vfs_fallocate(real.file, mode, offset, len);
> + revert_creds(old_cred);
> +
> + /* Update size */
> + ovl_copyattr(ovl_inode_real(inode), inode);
> +
> + fdput(real);
> +
> + return ret;
> +}
> +
> +static long ovl_real_ioctl(struct file *file, unsigned int cmd,
> + unsigned long arg)
> +{
> + struct fd real;
> + const struct cred *old_cred;
> + long ret;
> +
> + ret = ovl_real_fdget(file, &real);
> + if (ret)
> + return ret;
> +
> + old_cred = ovl_override_creds(file_inode(file)->i_sb);
> + ret = vfs_ioctl(real.file, cmd, arg);
> + revert_creds(old_cred);
> +
> + fdput(real);
> +
> + return ret;
> +}
> +
> +static long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
> +{
> + long ret;
> + struct inode *inode = file_inode(file);
> +
> + switch (cmd) {
> + case FS_IOC_GETFLAGS:
> + ret = ovl_real_ioctl(file, cmd, 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);
> + break;
> +
> + default:
> + ret = -ENOTTY;
> + }
> +
> + return ret;
> +}
> +
> +static long ovl_compat_ioctl(struct file *file, unsigned int cmd,
> + unsigned long arg)
> +{
> + switch (cmd) {
> + case FS_IOC32_GETFLAGS:
> + cmd = FS_IOC_GETFLAGS;
> + break;
> +
> + case FS_IOC32_SETFLAGS:
> + cmd = FS_IOC_SETFLAGS;
> + break;
> +
> + default:
> + return -ENOIOCTLCMD;
> + }
> +
> + return ovl_ioctl(file, cmd, arg);
> +}
> +
> +enum ovl_copyop {
> + OVL_COPY,
> + OVL_CLONE,
> + OVL_DEDUPE,
> +};
> +
> +static s64 ovl_copyfile(struct file *file_in, loff_t pos_in,
> + struct file *file_out, loff_t pos_out,
> + u64 len, unsigned int flags, enum ovl_copyop op)
> +{
> + struct inode *inode_out = file_inode(file_out);
> + struct fd real_in, real_out;
> + const struct cred *old_cred;
> + s64 ret;
> +
> + ret = ovl_real_fdget(file_out, &real_out);
> + if (ret)
> + return ret;
> +
> + ret = ovl_real_fdget(file_in, &real_in);
> + if (ret) {
> + fdput(real_out);
> + return ret;
> + }
> +
> + old_cred = ovl_override_creds(file_inode(file_out)->i_sb);
> + switch (op) {
> + case OVL_COPY:
> + ret = vfs_copy_file_range(real_in.file, pos_in,
> + real_out.file, pos_out, len, flags);
> + break;
> +
> + case OVL_CLONE:
> + ret = vfs_clone_file_range(real_in.file, pos_in,
> + real_out.file, pos_out, len);
> + break;
> +
> + case OVL_DEDUPE:
> + ret = vfs_dedupe_file_range_one(real_in.file, pos_in,
> + real_out.file, pos_out, len);
> + break;
> + }
> + revert_creds(old_cred);
> +
> + /* Update size */
> + ovl_copyattr(ovl_inode_real(inode_out), inode_out);
> +
> + fdput(real_in);
> + fdput(real_out);
> +
> + return ret;
> +}
> +
> +static ssize_t ovl_copy_file_range(struct file *file_in, loff_t pos_in,
> + struct file *file_out, loff_t pos_out,
> + size_t len, unsigned int flags)
> +{
> + return ovl_copyfile(file_in, pos_in, file_out, pos_out, len, flags,
> + OVL_COPY);
> +}
> +
> +static int ovl_clone_file_range(struct file *file_in, loff_t pos_in,
> + struct file *file_out, loff_t pos_out, u64 len)
> +{
> + return ovl_copyfile(file_in, pos_in, file_out, pos_out, len, 0,
> + OVL_CLONE);
> +}
> +
> +static loff_t ovl_dedupe_file_range(struct file *file_in, loff_t pos_in,
> + struct file *file_out, loff_t pos_out,
> + loff_t len)
> +{
> + /*
> + * Don't copy up because of a dedupe request, this wouldn't make sense
> + * most of the time (data would be duplicated instead of deduplicated).
> + */
> + if (!ovl_inode_upper(file_inode(file_in)) ||
> + !ovl_inode_upper(file_inode(file_out)))
> + return -EPERM;
> +
> + return ovl_copyfile(file_in, pos_in, file_out, pos_out, len, 0,
> + OVL_DEDUPE);
> +}
> +
> +const struct file_operations ovl_file_operations = {
> + .open = ovl_open,
> + .release = ovl_release,
> + .llseek = ovl_llseek,
> + .read_iter = ovl_read_iter,
> + .write_iter = ovl_write_iter,
> + .fsync = ovl_fsync,
> + .mmap = ovl_mmap,
> + .fallocate = ovl_fallocate,
> + .unlocked_ioctl = ovl_ioctl,
> + .compat_ioctl = ovl_compat_ioctl,
> +
> + .copy_file_range = ovl_copy_file_range,
> + .clone_file_range = ovl_clone_file_range,
> + .dedupe_file_range = ovl_dedupe_file_range,
> +};
> diff --cc fs/overlayfs/inode.c
> index e31d64206a01,d7cca60f28e6..e0bb217c01e2
> --- a/fs/overlayfs/inode.c
> +++ b/fs/overlayfs/inode.c
> @@@ -439,7 -384,39 +439,7 @@@ struct posix_acl *ovl_get_acl(struct in
> return acl;
> }
>
> - int ovl_update_time(struct inode *inode, struct timespec *ts, int flags)
> -static bool ovl_open_need_copy_up(struct dentry *dentry, int flags)
> -{
> - /* Copy up of disconnected dentry does not set upper alias */
> - if (ovl_dentry_upper(dentry) &&
> - (ovl_dentry_has_upper_alias(dentry) ||
> - (dentry->d_flags & DCACHE_DISCONNECTED)))
> - return false;
> -
> - if (special_file(d_inode(dentry)->i_mode))
> - return false;
> -
> - if (!(OPEN_FMODE(flags) & FMODE_WRITE) && !(flags & O_TRUNC))
> - return false;
> -
> - return true;
> -}
> -
> -int ovl_open_maybe_copy_up(struct dentry *dentry, unsigned int file_flags)
> -{
> - int err = 0;
> -
> - if (ovl_open_need_copy_up(dentry, file_flags)) {
> - err = ovl_want_write(dentry);
> - if (!err) {
> - err = ovl_copy_up_flags(dentry, file_flags);
> - ovl_drop_write(dentry);
> - }
> - }
> -
> - return err;
> -}
> -
> + int ovl_update_time(struct inode *inode, struct timespec64 *ts, int flags)
> {
> if (flags & S_ATIME) {
> struct ovl_fs *ofs = inode->i_sb->s_fs_info;
> diff --cc fs/overlayfs/overlayfs.h
> index ac9fbc3d08ea,9fe10247f9d4..f61839e1054c
> --- a/fs/overlayfs/overlayfs.h
> +++ b/fs/overlayfs/overlayfs.h
> @@@ -349,18 -330,10 +349,18 @@@ int ovl_xattr_get(struct dentry *dentry
> void *value, size_t size);
> ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size);
> struct posix_acl *ovl_get_acl(struct inode *inode, int type);
> - int ovl_update_time(struct inode *inode, struct timespec *ts, int flags);
> -int ovl_open_maybe_copy_up(struct dentry *dentry, unsigned int file_flags);
> + int ovl_update_time(struct inode *inode, struct timespec64 *ts, int flags);
> bool ovl_is_private_xattr(const char *name);
>
> +struct ovl_inode_params {
> + struct inode *newinode;
> + struct dentry *upperdentry;
> + struct ovl_path *lowerpath;
> + struct dentry *index;
> + unsigned int numlower;
> + char *redirect;
> + struct dentry *lowerdata;
> +};
> struct inode *ovl_new_inode(struct super_block *sb, umode_t mode, dev_t rdev);
> struct inode *ovl_lookup_inode(struct super_block *sb, struct dentry *real,
> bool is_upper);



--
Cheers,
Stephen Rothwell

Attachment: pgp0eJmb4SgrL.pgp
Description: OpenPGP digital signature