Merge remote-tracking branch 'ovl/misc' into work.misc
authorAl Viro <viro@zeniv.linux.org.uk>
Sat, 8 Oct 2016 15:00:01 +0000 (11:00 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Sat, 8 Oct 2016 15:00:01 +0000 (11:00 -0400)
25 files changed:
fs/attr.c
fs/btrfs/ctree.h
fs/btrfs/file.c
fs/btrfs/inode.c
fs/btrfs/tree-log.c
fs/cifs/cifsfs.h
fs/cifs/dir.c
fs/cifs/inode.c
fs/f2fs/node.c
fs/fat/namei_vfat.c
fs/inode.c
fs/internal.h
fs/locks.c
fs/namei.c
fs/namespace.c
fs/open.c
fs/overlayfs/super.c
fs/posix_acl.c
fs/utimes.c
include/linux/dcache.h
include/linux/fs.h
include/linux/fsnotify.h
include/uapi/linux/fs.h
security/integrity/ima/ima_appraise.c
security/integrity/ima/ima_main.c

index 42bb42b..3c42cab 100644 (file)
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -202,6 +202,21 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de
                        return -EPERM;
        }
 
+       /*
+        * If utimes(2) and friends are called with times == NULL (or both
+        * times are UTIME_NOW), then we need to check for write permission
+        */
+       if (ia_valid & ATTR_TOUCH) {
+               if (IS_IMMUTABLE(inode))
+                       return -EPERM;
+
+               if (!inode_owner_or_capable(inode)) {
+                       error = inode_permission(inode, MAY_WRITE);
+                       if (error)
+                               return error;
+               }
+       }
+
        if ((ia_valid & ATTR_MODE)) {
                umode_t amode = attr->ia_mode;
                /* Flag setting protected by i_mutex */
index 33fe035..e62fd50 100644 (file)
@@ -3161,7 +3161,6 @@ int btrfs_prealloc_file_range_trans(struct inode *inode,
                                    struct btrfs_trans_handle *trans, int mode,
                                    u64 start, u64 num_bytes, u64 min_size,
                                    loff_t actual_len, u64 *alloc_hint);
-int btrfs_inode_check_errors(struct inode *inode);
 extern const struct dentry_operations btrfs_dentry_operations;
 #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
 void btrfs_test_inode_set_ops(struct inode *inode);
index fea31a4..4843cb9 100644 (file)
@@ -2040,7 +2040,7 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
                 * flags for any errors that might have happened while doing
                 * writeback of file data.
                 */
-               ret = btrfs_inode_check_errors(inode);
+               ret = filemap_check_errors(inode->i_mapping);
                inode_unlock(inode);
                goto out;
        }
index e6811c4..0207622 100644 (file)
@@ -10543,21 +10543,6 @@ out_inode:
 
 }
 
-/* Inspired by filemap_check_errors() */
-int btrfs_inode_check_errors(struct inode *inode)
-{
-       int ret = 0;
-
-       if (test_bit(AS_ENOSPC, &inode->i_mapping->flags) &&
-           test_and_clear_bit(AS_ENOSPC, &inode->i_mapping->flags))
-               ret = -ENOSPC;
-       if (test_bit(AS_EIO, &inode->i_mapping->flags) &&
-           test_and_clear_bit(AS_EIO, &inode->i_mapping->flags))
-               ret = -EIO;
-
-       return ret;
-}
-
 static const struct inode_operations btrfs_dir_inode_operations = {
        .getattr        = btrfs_getattr,
        .lookup         = btrfs_lookup,
index ef9c55b..8a84ebd 100644 (file)
@@ -3961,7 +3961,7 @@ static int wait_ordered_extents(struct btrfs_trans_handle *trans,
                         * i_mapping flags, so that the next fsync won't get
                         * an outdated io error too.
                         */
-                       btrfs_inode_check_errors(inode);
+                       filemap_check_errors(inode->i_mapping);
                        *ordered_io_error = true;
                        break;
                }
@@ -4198,7 +4198,7 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans,
         * without writing to the log tree and the fsync must report the
         * file data write error and not commit the current transaction.
         */
-       ret = btrfs_inode_check_errors(inode);
+       ret = filemap_check_errors(inode->i_mapping);
        if (ret)
                ctx->io_err = ret;
 process:
index 9dcf974..c9c00a8 100644 (file)
@@ -41,6 +41,16 @@ cifs_uniqueid_to_ino_t(u64 fileid)
 
 }
 
+static inline void cifs_set_time(struct dentry *dentry, unsigned long time)
+{
+       dentry->d_fsdata = (void *) time;
+}
+
+static inline unsigned long cifs_get_time(struct dentry *dentry)
+{
+       return (unsigned long) dentry->d_fsdata;
+}
+
 extern struct file_system_type cifs_fs_type;
 extern const struct address_space_operations cifs_addr_ops;
 extern const struct address_space_operations cifs_addr_ops_smallbuf;
index 4716c54..789ff1d 100644 (file)
@@ -40,7 +40,7 @@ renew_parental_timestamps(struct dentry *direntry)
        /* BB check if there is a way to get the kernel to do this or if we
           really need this */
        do {
-               direntry->d_time = jiffies;
+               cifs_set_time(direntry, jiffies);
                direntry = direntry->d_parent;
        } while (!IS_ROOT(direntry));
 }
@@ -802,7 +802,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
 
        } else if (rc == -ENOENT) {
                rc = 0;
-               direntry->d_time = jiffies;
+               cifs_set_time(direntry, jiffies);
                d_add(direntry, NULL);
        /*      if it was once a directory (but how can we tell?) we could do
                shrink_dcache_parent(direntry); */
@@ -862,7 +862,7 @@ cifs_d_revalidate(struct dentry *direntry, unsigned int flags)
        if (flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET))
                return 0;
 
-       if (time_after(jiffies, direntry->d_time + HZ) || !lookupCacheEnabled)
+       if (time_after(jiffies, cifs_get_time(direntry) + HZ) || !lookupCacheEnabled)
                return 0;
 
        return 1;
index b87efd0..0b4a355 100644 (file)
@@ -1951,7 +1951,7 @@ int cifs_revalidate_dentry_attr(struct dentry *dentry)
 
        cifs_dbg(FYI, "Update attributes: %s inode 0x%p count %d dentry: 0x%p d_time %ld jiffies %ld\n",
                 full_path, inode, inode->i_count.counter,
-                dentry, dentry->d_time, jiffies);
+                dentry, cifs_get_time(dentry), jiffies);
 
        if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext)
                rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid);
index f75d197..67ed219 100644 (file)
@@ -1513,7 +1513,7 @@ int wait_on_node_pages_writeback(struct f2fs_sb_info *sbi, nid_t ino)
 {
        pgoff_t index = 0, end = ULONG_MAX;
        struct pagevec pvec;
-       int ret2 = 0, ret = 0;
+       int ret2, ret = 0;
 
        pagevec_init(&pvec, 0);
 
@@ -1542,10 +1542,7 @@ int wait_on_node_pages_writeback(struct f2fs_sb_info *sbi, nid_t ino)
                cond_resched();
        }
 
-       if (unlikely(test_and_clear_bit(AS_ENOSPC, &NODE_MAPPING(sbi)->flags)))
-               ret2 = -ENOSPC;
-       if (unlikely(test_and_clear_bit(AS_EIO, &NODE_MAPPING(sbi)->flags)))
-               ret2 = -EIO;
+       ret2 = filemap_check_errors(NODE_MAPPING(sbi));
        if (!ret)
                ret = ret2;
        return ret;
index 92b7363..4afdc3f 100644 (file)
 #include <linux/namei.h>
 #include "fat.h"
 
+static inline unsigned long vfat_d_version(struct dentry *dentry)
+{
+       return (unsigned long) dentry->d_fsdata;
+}
+
+static inline void vfat_d_version_set(struct dentry *dentry,
+                                     unsigned long version)
+{
+       dentry->d_fsdata = (void *) version;
+}
+
 /*
  * If new entry was created in the parent, it could create the 8.3
  * alias (the shortname of logname).  So, the parent may have the
@@ -33,7 +44,7 @@ static int vfat_revalidate_shortname(struct dentry *dentry)
 {
        int ret = 1;
        spin_lock(&dentry->d_lock);
-       if (dentry->d_time != d_inode(dentry->d_parent)->i_version)
+       if (vfat_d_version(dentry) != d_inode(dentry->d_parent)->i_version)
                ret = 0;
        spin_unlock(&dentry->d_lock);
        return ret;
@@ -759,7 +770,7 @@ static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry,
 out:
        mutex_unlock(&MSDOS_SB(sb)->s_lock);
        if (!inode)
-               dentry->d_time = dir->i_version;
+               vfat_d_version_set(dentry, dir->i_version);
        return d_splice_alias(inode, dentry);
 error:
        mutex_unlock(&MSDOS_SB(sb)->s_lock);
@@ -823,7 +834,7 @@ static int vfat_rmdir(struct inode *dir, struct dentry *dentry)
        clear_nlink(inode);
        inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
        fat_detach(inode);
-       dentry->d_time = dir->i_version;
+       vfat_d_version_set(dentry, dir->i_version);
 out:
        mutex_unlock(&MSDOS_SB(sb)->s_lock);
 
@@ -849,7 +860,7 @@ static int vfat_unlink(struct inode *dir, struct dentry *dentry)
        clear_nlink(inode);
        inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
        fat_detach(inode);
-       dentry->d_time = dir->i_version;
+       vfat_d_version_set(dentry, dir->i_version);
 out:
        mutex_unlock(&MSDOS_SB(sb)->s_lock);
 
index 691c007..a3c7ba7 100644 (file)
@@ -1562,17 +1562,37 @@ sector_t bmap(struct inode *inode, sector_t block)
 }
 EXPORT_SYMBOL(bmap);
 
+/*
+ * Update times in overlayed inode from underlying real inode
+ */
+static void update_ovl_inode_times(struct dentry *dentry, struct inode *inode,
+                              bool rcu)
+{
+       if (!rcu) {
+               struct inode *realinode = d_real_inode(dentry);
+
+               if (unlikely(inode != realinode) &&
+                   (!timespec_equal(&inode->i_mtime, &realinode->i_mtime) ||
+                    !timespec_equal(&inode->i_ctime, &realinode->i_ctime))) {
+                       inode->i_mtime = realinode->i_mtime;
+                       inode->i_ctime = realinode->i_ctime;
+               }
+       }
+}
+
 /*
  * With relative atime, only update atime if the previous atime is
  * earlier than either the ctime or mtime or if at least a day has
  * passed since the last atime update.
  */
-static int relatime_need_update(struct vfsmount *mnt, struct inode *inode,
-                            struct timespec now)
+static int relatime_need_update(const struct path *path, struct inode *inode,
+                               struct timespec now, bool rcu)
 {
 
-       if (!(mnt->mnt_flags & MNT_RELATIME))
+       if (!(path->mnt->mnt_flags & MNT_RELATIME))
                return 1;
+
+       update_ovl_inode_times(path->dentry, inode, rcu);
        /*
         * Is mtime younger than atime? If yes, update atime:
         */
@@ -1639,7 +1659,8 @@ static int update_time(struct inode *inode, struct timespec *time, int flags)
  *     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 __atime_needs_update(const struct path *path, struct inode *inode,
+                         bool rcu)
 {
        struct vfsmount *mnt = path->mnt;
        struct timespec now;
@@ -1665,7 +1686,7 @@ bool atime_needs_update(const struct path *path, struct inode *inode)
 
        now = current_fs_time(inode->i_sb);
 
-       if (!relatime_need_update(mnt, inode, now))
+       if (!relatime_need_update(path, inode, now, rcu))
                return false;
 
        if (timespec_equal(&inode->i_atime, &now))
@@ -1680,7 +1701,7 @@ void touch_atime(const struct path *path)
        struct inode *inode = d_inode(path->dentry);
        struct timespec now;
 
-       if (!atime_needs_update(path, inode))
+       if (!__atime_needs_update(path, inode, false))
                return;
 
        if (!sb_start_write_trylock(inode->i_sb))
index 3958878..18cfde9 100644 (file)
@@ -120,6 +120,15 @@ extern long prune_icache_sb(struct super_block *sb, struct shrink_control *sc);
 extern void inode_add_lru(struct inode *inode);
 extern int dentry_needs_remove_privs(struct dentry *dentry);
 
+extern bool __atime_needs_update(const struct path *, struct inode *, bool);
+static inline bool atime_needs_update_rcu(const struct path *path,
+                                         struct inode *inode)
+{
+       return __atime_needs_update(path, inode, true);
+}
+
+extern bool atime_needs_update_rcu(const struct path *, struct inode *);
+
 /*
  * fs-writeback.c
  */
index ee1b15f..b242d5b 100644 (file)
 #define IS_LEASE(fl)   (fl->fl_flags & (FL_LEASE|FL_DELEG|FL_LAYOUT))
 #define IS_OFDLCK(fl)  (fl->fl_flags & FL_OFDLCK)
 
+static inline bool is_remote_lock(struct file *filp)
+{
+       return likely(!(filp->f_path.dentry->d_sb->s_flags & MS_NOREMOTELOCK));
+}
+
 static bool lease_breaking(struct file_lock *fl)
 {
        return fl->fl_flags & (FL_UNLOCK_PENDING | FL_DOWNGRADE_PENDING);
@@ -791,7 +796,7 @@ posix_test_lock(struct file *filp, struct file_lock *fl)
 {
        struct file_lock *cfl;
        struct file_lock_context *ctx;
-       struct inode *inode = file_inode(filp);
+       struct inode *inode = locks_inode(filp);
 
        ctx = smp_load_acquire(&inode->i_flctx);
        if (!ctx || list_empty_careful(&ctx->flc_posix)) {
@@ -1192,7 +1197,7 @@ static int posix_lock_inode(struct inode *inode, struct file_lock *request,
 int posix_lock_file(struct file *filp, struct file_lock *fl,
                        struct file_lock *conflock)
 {
-       return posix_lock_inode(file_inode(filp), fl, conflock);
+       return posix_lock_inode(locks_inode(filp), fl, conflock);
 }
 EXPORT_SYMBOL(posix_lock_file);
 
@@ -1232,7 +1237,7 @@ static int posix_lock_inode_wait(struct inode *inode, struct file_lock *fl)
 int locks_mandatory_locked(struct file *file)
 {
        int ret;
-       struct inode *inode = file_inode(file);
+       struct inode *inode = locks_inode(file);
        struct file_lock_context *ctx;
        struct file_lock *fl;
 
@@ -1572,7 +1577,7 @@ EXPORT_SYMBOL(lease_get_mtime);
 int fcntl_getlease(struct file *filp)
 {
        struct file_lock *fl;
-       struct inode *inode = file_inode(filp);
+       struct inode *inode = locks_inode(filp);
        struct file_lock_context *ctx;
        int type = F_UNLCK;
        LIST_HEAD(dispose);
@@ -1580,7 +1585,7 @@ int fcntl_getlease(struct file *filp)
        ctx = smp_load_acquire(&inode->i_flctx);
        if (ctx && !list_empty_careful(&ctx->flc_lease)) {
                spin_lock(&ctx->flc_lock);
-               time_out_leases(file_inode(filp), &dispose);
+               time_out_leases(inode, &dispose);
                list_for_each_entry(fl, &ctx->flc_lease, fl_list) {
                        if (fl->fl_file != filp)
                                continue;
@@ -1613,7 +1618,8 @@ check_conflicting_open(const struct dentry *dentry, const long arg, int flags)
        if (flags & FL_LAYOUT)
                return 0;
 
-       if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0))
+       if ((arg == F_RDLCK) &&
+           (atomic_read(&d_real_inode(dentry)->i_writecount) > 0))
                return -EAGAIN;
 
        if ((arg == F_WRLCK) && ((d_count(dentry) > 1) ||
@@ -1628,7 +1634,7 @@ generic_add_lease(struct file *filp, long arg, struct file_lock **flp, void **pr
 {
        struct file_lock *fl, *my_fl = NULL, *lease;
        struct dentry *dentry = filp->f_path.dentry;
-       struct inode *inode = file_inode(filp);
+       struct inode *inode = dentry->d_inode;
        struct file_lock_context *ctx;
        bool is_deleg = (*flp)->fl_flags & FL_DELEG;
        int error;
@@ -1742,7 +1748,7 @@ static int generic_delete_lease(struct file *filp, void *owner)
 {
        int error = -EAGAIN;
        struct file_lock *fl, *victim = NULL;
-       struct inode *inode = file_inode(filp);
+       struct inode *inode = locks_inode(filp);
        struct file_lock_context *ctx;
        LIST_HEAD(dispose);
 
@@ -1782,7 +1788,7 @@ static int generic_delete_lease(struct file *filp, void *owner)
 int generic_setlease(struct file *filp, long arg, struct file_lock **flp,
                        void **priv)
 {
-       struct inode *inode = file_inode(filp);
+       struct inode *inode = locks_inode(filp);
        int error;
 
        if ((!uid_eq(current_fsuid(), inode->i_uid)) && !capable(CAP_LEASE))
@@ -1830,7 +1836,7 @@ EXPORT_SYMBOL(generic_setlease);
 int
 vfs_setlease(struct file *filp, long arg, struct file_lock **lease, void **priv)
 {
-       if (filp->f_op->setlease)
+       if (filp->f_op->setlease && is_remote_lock(filp))
                return filp->f_op->setlease(filp, arg, lease, priv);
        else
                return generic_setlease(filp, arg, lease, priv);
@@ -1979,7 +1985,7 @@ SYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd)
        if (error)
                goto out_free;
 
-       if (f.file->f_op->flock)
+       if (f.file->f_op->flock && is_remote_lock(f.file))
                error = f.file->f_op->flock(f.file,
                                          (can_sleep) ? F_SETLKW : F_SETLK,
                                          lock);
@@ -2005,7 +2011,7 @@ SYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd)
  */
 int vfs_test_lock(struct file *filp, struct file_lock *fl)
 {
-       if (filp->f_op->lock)
+       if (filp->f_op->lock && is_remote_lock(filp))
                return filp->f_op->lock(filp, F_GETLK, fl);
        posix_test_lock(filp, fl);
        return 0;
@@ -2129,7 +2135,7 @@ out:
  */
 int vfs_lock_file(struct file *filp, unsigned int cmd, struct file_lock *fl, struct file_lock *conf)
 {
-       if (filp->f_op->lock)
+       if (filp->f_op->lock && is_remote_lock(filp))
                return filp->f_op->lock(filp, cmd, fl);
        else
                return posix_lock_file(filp, fl, conf);
@@ -2191,7 +2197,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
        if (file_lock == NULL)
                return -ENOLCK;
 
-       inode = file_inode(filp);
+       inode = locks_inode(filp);
 
        /*
         * This might block, so we do it before checking the inode.
@@ -2343,7 +2349,7 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd,
        if (copy_from_user(&flock, l, sizeof(flock)))
                goto out;
 
-       inode = file_inode(filp);
+       inode = locks_inode(filp);
 
        /* Don't allow mandatory locks on files that may be memory mapped
         * and shared.
@@ -2426,6 +2432,7 @@ out:
 void locks_remove_posix(struct file *filp, fl_owner_t owner)
 {
        int error;
+       struct inode *inode = locks_inode(filp);
        struct file_lock lock;
        struct file_lock_context *ctx;
 
@@ -2434,7 +2441,7 @@ void locks_remove_posix(struct file *filp, fl_owner_t owner)
         * posix_lock_file().  Another process could be setting a lock on this
         * file at the same time, but we wouldn't remove that lock anyway.
         */
-       ctx =  smp_load_acquire(&file_inode(filp)->i_flctx);
+       ctx =  smp_load_acquire(&inode->i_flctx);
        if (!ctx || list_empty(&ctx->flc_posix))
                return;
 
@@ -2452,7 +2459,7 @@ void locks_remove_posix(struct file *filp, fl_owner_t owner)
 
        if (lock.fl_ops && lock.fl_ops->fl_release_private)
                lock.fl_ops->fl_release_private(&lock);
-       trace_locks_remove_posix(file_inode(filp), &lock, error);
+       trace_locks_remove_posix(inode, &lock, error);
 }
 
 EXPORT_SYMBOL(locks_remove_posix);
@@ -2469,12 +2476,12 @@ locks_remove_flock(struct file *filp, struct file_lock_context *flctx)
                .fl_type = F_UNLCK,
                .fl_end = OFFSET_MAX,
        };
-       struct inode *inode = file_inode(filp);
+       struct inode *inode = locks_inode(filp);
 
        if (list_empty(&flctx->flc_flock))
                return;
 
-       if (filp->f_op->flock)
+       if (filp->f_op->flock && is_remote_lock(filp))
                filp->f_op->flock(filp, F_SETLKW, &fl);
        else
                flock_lock_inode(inode, &fl);
@@ -2508,7 +2515,7 @@ void locks_remove_file(struct file *filp)
 {
        struct file_lock_context *ctx;
 
-       ctx = smp_load_acquire(&file_inode(filp)->i_flctx);
+       ctx = smp_load_acquire(&locks_inode(filp)->i_flctx);
        if (!ctx)
                return;
 
@@ -2552,7 +2559,7 @@ EXPORT_SYMBOL(posix_unblock_lock);
  */
 int vfs_cancel_lock(struct file *filp, struct file_lock *fl)
 {
-       if (filp->f_op->lock)
+       if (filp->f_op->lock && is_remote_lock(filp))
                return filp->f_op->lock(filp, F_CANCELLK, fl);
        return 0;
 }
@@ -2580,7 +2587,7 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl,
                fl_pid = fl->fl_pid;
 
        if (fl->fl_file != NULL)
-               inode = file_inode(fl->fl_file);
+               inode = locks_inode(fl->fl_file);
 
        seq_printf(f, "%lld:%s ", id, pfx);
        if (IS_POSIX(fl)) {
@@ -2682,7 +2689,7 @@ static void __show_fd_locks(struct seq_file *f,
 void show_fd_locks(struct seq_file *f,
                  struct file *filp, struct files_struct *files)
 {
-       struct inode *inode = file_inode(filp);
+       struct inode *inode = locks_inode(filp);
        struct file_lock_context *ctx;
        int id = 0;
 
index adb0414..4bbcae1 100644 (file)
@@ -1015,7 +1015,7 @@ const char *get_link(struct nameidata *nd)
        if (!(nd->flags & LOOKUP_RCU)) {
                touch_atime(&last->link);
                cond_resched();
-       } else if (atime_needs_update(&last->link, inode)) {
+       } else if (atime_needs_update_rcu(&last->link, inode)) {
                if (unlikely(unlazy_walk(nd, NULL, 0)))
                        return ERR_PTR(-ECHILD);
                touch_atime(&last->link);
index 7bb2cda..dcd9afe 100644 (file)
@@ -2700,7 +2700,7 @@ long do_mount(const char *dev_name, const char __user *dir_name,
 
        flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE | MS_BORN |
                   MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT |
-                  MS_STRICTATIME);
+                  MS_STRICTATIME | MS_NOREMOTELOCK);
 
        if (flags & MS_REMOUNT)
                retval = do_remount(&path, flags & ~MS_REMOUNT, mnt_flags,
index 4fd6e25..8aeb08b 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -68,6 +68,7 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
 long vfs_truncate(const struct path *path, loff_t length)
 {
        struct inode *inode;
+       struct dentry *upperdentry;
        long error;
 
        inode = path->dentry->d_inode;
@@ -90,7 +91,17 @@ long vfs_truncate(const struct path *path, loff_t length)
        if (IS_APPEND(inode))
                goto mnt_drop_write_and_out;
 
-       error = get_write_access(inode);
+       /*
+        * If this is an overlayfs then do as if opening the file so we get
+        * write access on the upper inode, not on the overlay inode.  For
+        * non-overlay filesystems d_real() is an identity function.
+        */
+       upperdentry = d_real(path->dentry, NULL, O_WRONLY);
+       error = PTR_ERR(upperdentry);
+       if (IS_ERR(upperdentry))
+               goto mnt_drop_write_and_out;
+
+       error = get_write_access(upperdentry->d_inode);
        if (error)
                goto mnt_drop_write_and_out;
 
@@ -109,7 +120,7 @@ long vfs_truncate(const struct path *path, loff_t length)
                error = do_truncate(path->dentry, length, 0, NULL);
 
 put_write_and_out:
-       put_write_access(inode);
+       put_write_access(upperdentry->d_inode);
 mnt_drop_write_and_out:
        mnt_drop_write(path->mnt);
 out:
@@ -726,7 +737,7 @@ static int do_dentry_open(struct file *f,
        if (error)
                goto cleanup_all;
 
-       error = break_lease(inode, f->f_flags);
+       error = break_lease(locks_inode(f), f->f_flags);
        if (error)
                goto cleanup_all;
 
index e2a94a2..3d0b9de 100644 (file)
@@ -1320,7 +1320,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_xattr = ovl_xattr_handlers;
        sb->s_root = root_dentry;
        sb->s_fs_info = ufs;
-       sb->s_flags |= MS_POSIXACL;
+       sb->s_flags |= MS_POSIXACL | MS_NOREMOTELOCK;
 
        return 0;
 
index 8cdcbb1..8719392 100644 (file)
@@ -598,13 +598,14 @@ posix_acl_create(struct inode *dir, umode_t *mode,
        if (IS_ERR(p))
                return PTR_ERR(p);
 
+       ret = -ENOMEM;
        clone = posix_acl_clone(p, GFP_NOFS);
        if (!clone)
-               goto no_mem;
+               goto err_release;
 
        ret = posix_acl_create_masq(clone, mode);
        if (ret < 0)
-               goto no_mem_clone;
+               goto err_release_clone;
 
        if (ret == 0)
                posix_acl_release(clone);
@@ -618,11 +619,11 @@ posix_acl_create(struct inode *dir, umode_t *mode,
 
        return 0;
 
-no_mem_clone:
+err_release_clone:
        posix_acl_release(clone);
-no_mem:
+err_release:
        posix_acl_release(p);
-       return -ENOMEM;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(posix_acl_create);
 
index 794f5f5..ba54b9e 100644 (file)
@@ -87,21 +87,7 @@ static int utimes_common(struct path *path, struct timespec *times)
                 */
                newattrs.ia_valid |= ATTR_TIMES_SET;
        } else {
-               /*
-                * If times is NULL (or both times are UTIME_NOW),
-                * then we need to check permissions, because
-                * inode_change_ok() won't do it.
-                */
-               error = -EPERM;
-                if (IS_IMMUTABLE(inode))
-                       goto mnt_drop_write_and_out;
-
-               error = -EACCES;
-               if (!inode_owner_or_capable(inode)) {
-                       error = inode_permission(inode, MAY_WRITE);
-                       if (error)
-                               goto mnt_drop_write_and_out;
-               }
+               newattrs.ia_valid |= ATTR_TOUCH;
        }
 retry_deleg:
        inode_lock(inode);
@@ -113,7 +99,6 @@ retry_deleg:
                        goto retry_deleg;
        }
 
-mnt_drop_write_and_out:
        mnt_drop_write(path->mnt);
 out:
        return error;
index 5ff3e9a..5beed7b 100644 (file)
@@ -584,9 +584,10 @@ static inline struct dentry *d_real(struct dentry *dentry,
  * If dentry is on an union/overlay, then return the underlying, real inode.
  * Otherwise return d_inode().
  */
-static inline struct inode *d_real_inode(struct dentry *dentry)
+static inline struct inode *d_real_inode(const struct dentry *dentry)
 {
-       return d_backing_inode(d_real(dentry, NULL, 0));
+       /* This usage of d_real() results in const dentry */
+       return d_backing_inode(d_real((struct dentry *) dentry, NULL, 0));
 }
 
 
index 2f6f059..9347f4a 100644 (file)
@@ -224,6 +224,7 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
 #define ATTR_KILL_PRIV (1 << 14)
 #define ATTR_OPEN      (1 << 15) /* Truncating from open(O_TRUNC) */
 #define ATTR_TIMES_SET (1 << 16)
+#define ATTR_TOUCH     (1 << 17)
 
 /*
  * Whiteout is represented by a char device.  The following constants define the
@@ -1064,6 +1065,18 @@ struct file_lock_context {
 
 extern void send_sigio(struct fown_struct *fown, int fd, int band);
 
+/*
+ * Return the inode to use for locking
+ *
+ * For overlayfs this should be the overlay inode, not the real inode returned
+ * by file_inode().  For any other fs file_inode(filp) and locks_inode(filp) are
+ * equal.
+ */
+static inline struct inode *locks_inode(const struct file *f)
+{
+       return f->f_path.dentry->d_inode;
+}
+
 #ifdef CONFIG_FILE_LOCKING
 extern int fcntl_getlk(struct file *, unsigned int, struct flock __user *);
 extern int fcntl_setlk(unsigned int, struct file *, unsigned int,
@@ -1251,7 +1264,7 @@ static inline struct dentry *file_dentry(const struct file *file)
 
 static inline int locks_lock_file_wait(struct file *filp, struct file_lock *fl)
 {
-       return locks_lock_inode_wait(file_inode(filp), fl);
+       return locks_lock_inode_wait(locks_inode(filp), fl);
 }
 
 struct fasync_struct {
@@ -2006,7 +2019,6 @@ enum file_time_flags {
        S_VERSION = 8,
 };
 
-extern bool atime_needs_update(const struct path *, struct inode *);
 extern void touch_atime(const struct path *);
 static inline void file_accessed(struct file *file)
 {
@@ -2155,7 +2167,7 @@ static inline int mandatory_lock(struct inode *ino)
 
 static inline int locks_verify_locked(struct file *file)
 {
-       if (mandatory_lock(file_inode(file)))
+       if (mandatory_lock(locks_inode(file)))
                return locks_mandatory_locked(file);
        return 0;
 }
index eed9e85..b8bcc05 100644 (file)
@@ -29,7 +29,11 @@ static inline int fsnotify_parent(struct path *path, struct dentry *dentry, __u3
 static inline int fsnotify_perm(struct file *file, int mask)
 {
        struct path *path = &file->f_path;
-       struct inode *inode = file_inode(file);
+       /*
+        * Do not use file_inode() here or anywhere in this file to get the
+        * inode.  That would break *notity on overlayfs.
+        */
+       struct inode *inode = path->dentry->d_inode;
        __u32 fsnotify_mask = 0;
        int ret;
 
@@ -173,7 +177,7 @@ static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)
 static inline void fsnotify_access(struct file *file)
 {
        struct path *path = &file->f_path;
-       struct inode *inode = file_inode(file);
+       struct inode *inode = path->dentry->d_inode;
        __u32 mask = FS_ACCESS;
 
        if (S_ISDIR(inode->i_mode))
@@ -191,7 +195,7 @@ static inline void fsnotify_access(struct file *file)
 static inline void fsnotify_modify(struct file *file)
 {
        struct path *path = &file->f_path;
-       struct inode *inode = file_inode(file);
+       struct inode *inode = path->dentry->d_inode;
        __u32 mask = FS_MODIFY;
 
        if (S_ISDIR(inode->i_mode))
@@ -209,7 +213,7 @@ static inline void fsnotify_modify(struct file *file)
 static inline void fsnotify_open(struct file *file)
 {
        struct path *path = &file->f_path;
-       struct inode *inode = file_inode(file);
+       struct inode *inode = path->dentry->d_inode;
        __u32 mask = FS_OPEN;
 
        if (S_ISDIR(inode->i_mode))
@@ -225,7 +229,7 @@ static inline void fsnotify_open(struct file *file)
 static inline void fsnotify_close(struct file *file)
 {
        struct path *path = &file->f_path;
-       struct inode *inode = file_inode(file);
+       struct inode *inode = path->dentry->d_inode;
        fmode_t mode = file->f_mode;
        __u32 mask = (mode & FMODE_WRITE) ? FS_CLOSE_WRITE : FS_CLOSE_NOWRITE;
 
index 3b00f7c..2473272 100644 (file)
@@ -132,6 +132,7 @@ struct inodes_stat_t {
 #define MS_LAZYTIME    (1<<25) /* Update the on-disk [acm]times lazily */
 
 /* These sb flags are internal to the kernel */
+#define MS_NOREMOTELOCK        (1<<27)
 #define MS_NOSEC       (1<<28)
 #define MS_BORN                (1<<29)
 #define MS_ACTIVE      (1<<30)
index 4b9b4a4..ef1e4e7 100644 (file)
@@ -190,7 +190,7 @@ int ima_appraise_measurement(enum ima_hooks func,
 {
        static const char op[] = "appraise_data";
        char *cause = "unknown";
-       struct dentry *dentry = file->f_path.dentry;
+       struct dentry *dentry = file_dentry(file);
        struct inode *inode = d_backing_inode(dentry);
        enum integrity_status status = INTEGRITY_UNKNOWN;
        int rc = xattr_len, hash_start = 0;
@@ -295,7 +295,7 @@ out:
  */
 void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file)
 {
-       struct dentry *dentry = file->f_path.dentry;
+       struct dentry *dentry = file_dentry(file);
        int rc = 0;
 
        /* do not collect and update hash for digital signatures */
index 596ef61..423d111 100644 (file)
@@ -228,7 +228,7 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
        if ((action & IMA_APPRAISE_SUBMASK) ||
                    strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) != 0)
                /* read 'security.ima' */
-               xattr_len = ima_read_xattr(file->f_path.dentry, &xattr_value);
+               xattr_len = ima_read_xattr(file_dentry(file), &xattr_value);
 
        hash_algo = ima_get_hash_algo(xattr_value, xattr_len);