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:
pgpBiuXQK0qd6.pgp
Description: OpenPGP digital signature