]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 19 Dec 2016 16:23:53 +0000 (08:23 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 19 Dec 2016 16:23:53 +0000 (08:23 -0800)
Pull quota, fsnotify and ext2 updates from Jan Kara:
 "Changes to locking of some quota operations from dedicated quota mutex
  to s_umount semaphore, a fsnotify fix and a simple ext2 fix"

* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs:
  quota: Fix bogus warning in dquot_disable()
  fsnotify: Fix possible use-after-free in inode iteration on umount
  ext2: reject inodes with negative size
  quota: Remove dqonoff_mutex
  ocfs2: Use s_umount for quota recovery protection
  quota: Remove dqonoff_mutex from dquot_scan_active()
  ocfs2: Protect periodic quota syncing with s_umount semaphore
  quota: Use s_umount protection for quota operations
  quota: Hold s_umount in exclusive mode when enabling / disabling quotas
  fs: Provide function to get superblock with exclusive s_umount

1  2 
fs/ext2/inode.c
fs/ocfs2/super.c
fs/quota/dquot.c
fs/quota/quota.c
include/linux/fs.h
include/linux/quota.h

diff --combined fs/ext2/inode.c
index e173afe9266109f4e7b948433d4d422e90bacc72,01f6d4be7f9aae0bb0a39899e2ab003da6045974..0093ea2512a85809e16605088074a8335513e81c
@@@ -732,13 -732,16 +732,13 @@@ static int ext2_get_blocks(struct inod
        }
  
        if (IS_DAX(inode)) {
 -              int i;
 -
                /*
                 * We must unmap blocks before zeroing so that writeback cannot
                 * overwrite zeros with stale data from block device page cache.
                 */
 -              for (i = 0; i < count; i++) {
 -                      unmap_underlying_metadata(inode->i_sb->s_bdev,
 -                                      le32_to_cpu(chain[depth-1].key) + i);
 -              }
 +              clean_bdev_aliases(inode->i_sb->s_bdev,
 +                                 le32_to_cpu(chain[depth-1].key),
 +                                 count);
                /*
                 * block must be initialised before we put it in the tree
                 * so that it's not found by another thread before it's
@@@ -847,9 -850,6 +847,9 @@@ struct iomap_ops ext2_iomap_ops = 
        .iomap_begin            = ext2_iomap_begin,
        .iomap_end              = ext2_iomap_end,
  };
 +#else
 +/* Define empty ops for !CONFIG_FS_DAX case to avoid ugly ifdefs */
 +struct iomap_ops ext2_iomap_ops;
  #endif /* CONFIG_FS_DAX */
  
  int ext2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
@@@ -1293,11 -1293,9 +1293,11 @@@ static int ext2_setsize(struct inode *i
  
        inode_dio_wait(inode);
  
 -      if (IS_DAX(inode))
 -              error = dax_truncate_page(inode, newsize, ext2_get_block);
 -      else if (test_opt(inode->i_sb, NOBH))
 +      if (IS_DAX(inode)) {
 +              error = iomap_zero_range(inode, newsize,
 +                                       PAGE_ALIGN(newsize) - newsize, NULL,
 +                                       &ext2_iomap_ops);
 +      } else if (test_opt(inode->i_sb, NOBH))
                error = nobh_truncate_page(inode->i_mapping,
                                newsize, ext2_get_block);
        else
@@@ -1478,6 -1476,10 +1478,10 @@@ struct inode *ext2_iget (struct super_b
                inode->i_size |= ((__u64)le32_to_cpu(raw_inode->i_size_high)) << 32;
        else
                ei->i_dir_acl = le32_to_cpu(raw_inode->i_dir_acl);
+       if (i_size_read(inode) < 0) {
+               ret = -EFSCORRUPTED;
+               goto bad_inode;
+       }
        ei->i_dtime = 0;
        inode->i_generation = le32_to_cpu(raw_inode->i_generation);
        ei->i_state = 0;
diff --combined fs/ocfs2/super.c
index c894d945b084d71d7672f588d561acccf143be43,5b9c0dfdb541b68e960562ccec790d7256a92cd7..a24e42f953418b1d675481ed826d47106c1730f4
@@@ -337,7 -337,7 +337,7 @@@ static int ocfs2_osb_dump(struct ocfs2_
                out += snprintf(buf + out, len - out, "Disabled\n");
        else
                out += snprintf(buf + out, len - out, "%lu seconds ago\n",
 -                              (get_seconds() - os->os_scantime.tv_sec));
 +                              (unsigned long)(ktime_get_seconds() - os->os_scantime));
  
        out += snprintf(buf + out, len - out, "%10s => %3s  %10s\n",
                        "Slots", "Num", "RecoGen");
@@@ -985,7 -985,6 +985,6 @@@ static void ocfs2_disable_quotas(struc
        for (type = 0; type < OCFS2_MAXQUOTAS; type++) {
                if (!sb_has_quota_loaded(sb, type))
                        continue;
-               /* Cancel periodic syncing before we grab dqonoff_mutex */
                oinfo = sb_dqinfo(sb, type)->dqi_priv;
                cancel_delayed_work_sync(&oinfo->dqi_sync_work);
                inode = igrab(sb->s_dquot.files[type]);
diff --combined fs/quota/dquot.c
index 8738a0d62c095021fe39208f8ec6cf4a18beab70,1ed5494aa773f354a50d26ed4e2eca063bacf80a..406fed92362a3da805b7f1834268acd2e996d46f
   * spinlock to internal buffers before writing.
   *
   * Lock ordering (including related VFS locks) is the following:
-  *   dqonoff_mutex > i_mutex > journal_lock > dquot->dq_lock > dqio_mutex
-  * dqonoff_mutex > i_mutex comes from dquot_quota_sync, dquot_enable, etc.
+  *   s_umount > i_mutex > journal_lock > dquot->dq_lock > dqio_mutex
   */
  
  static __cacheline_aligned_in_smp DEFINE_SPINLOCK(dq_list_lock);
@@@ -572,7 -571,8 +571,8 @@@ int dquot_scan_active(struct super_bloc
        struct dquot *dquot, *old_dquot = NULL;
        int ret = 0;
  
-       mutex_lock(&sb_dqopt(sb)->dqonoff_mutex);
+       WARN_ON_ONCE(!rwsem_is_locked(&sb->s_umount));
        spin_lock(&dq_list_lock);
        list_for_each_entry(dquot, &inuse_list, dq_inuse) {
                if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags))
        spin_unlock(&dq_list_lock);
  out:
        dqput(old_dquot);
-       mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
        return ret;
  }
  EXPORT_SYMBOL(dquot_scan_active);
@@@ -617,7 -616,8 +616,8 @@@ int dquot_writeback_dquots(struct super
        int cnt;
        int err, ret = 0;
  
-       mutex_lock(&dqopt->dqonoff_mutex);
+       WARN_ON_ONCE(!rwsem_is_locked(&sb->s_umount));
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
                if (type != -1 && cnt != type)
                        continue;
                    && info_dirty(&dqopt->info[cnt]))
                        sb->dq_op->write_info(sb, cnt);
        dqstats_inc(DQST_SYNCS);
-       mutex_unlock(&dqopt->dqonoff_mutex);
  
        return ret;
  }
@@@ -683,7 -682,6 +682,6 @@@ int dquot_quota_sync(struct super_bloc
         * Now when everything is written we can discard the pagecache so
         * that userspace sees the changes.
         */
-       mutex_lock(&dqopt->dqonoff_mutex);
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
                if (type != -1 && cnt != type)
                        continue;
                truncate_inode_pages(&dqopt->files[cnt]->i_data, 0);
                inode_unlock(dqopt->files[cnt]);
        }
-       mutex_unlock(&dqopt->dqonoff_mutex);
  
        return 0;
  }
@@@ -935,7 -932,7 +932,7 @@@ static int dqinit_needed(struct inode *
        return 0;
  }
  
- /* This routine is guarded by dqonoff_mutex mutex */
+ /* This routine is guarded by s_umount semaphore */
  static void add_dquot_ref(struct super_block *sb, int type)
  {
        struct inode *inode, *old_inode = NULL;
@@@ -2050,21 -2047,13 +2047,13 @@@ int dquot_get_next_id(struct super_bloc
        struct quota_info *dqopt = sb_dqopt(sb);
        int err;
  
-       mutex_lock(&dqopt->dqonoff_mutex);
-       if (!sb_has_quota_active(sb, qid->type)) {
-               err = -ESRCH;
-               goto out;
-       }
-       if (!dqopt->ops[qid->type]->get_next_id) {
-               err = -ENOSYS;
-               goto out;
-       }
+       if (!sb_has_quota_active(sb, qid->type))
+               return -ESRCH;
+       if (!dqopt->ops[qid->type]->get_next_id)
+               return -ENOSYS;
        mutex_lock(&dqopt->dqio_mutex);
        err = dqopt->ops[qid->type]->get_next_id(sb, qid);
        mutex_unlock(&dqopt->dqio_mutex);
- out:
-       mutex_unlock(&dqopt->dqonoff_mutex);
        return err;
  }
  EXPORT_SYMBOL(dquot_get_next_id);
@@@ -2107,6 -2096,10 +2096,10 @@@ int dquot_disable(struct super_block *s
        struct quota_info *dqopt = sb_dqopt(sb);
        struct inode *toputinode[MAXQUOTAS];
  
+       /* s_umount should be held in exclusive mode */
+       if (WARN_ON_ONCE(down_read_trylock(&sb->s_umount)))
+               up_read(&sb->s_umount);
        /* Cannot turn off usage accounting without turning off limits, or
         * suspend quotas and simultaneously turn quotas off. */
        if ((flags & DQUOT_USAGE_ENABLED && !(flags & DQUOT_LIMITS_ENABLED))
            DQUOT_USAGE_ENABLED)))
                return -EINVAL;
  
-       /* We need to serialize quota_off() for device */
-       mutex_lock(&dqopt->dqonoff_mutex);
        /*
         * Skip everything if there's nothing to do. We have to do this because
         * sometimes we are called when fill_super() failed and calling
         * sync_fs() in such cases does no good.
         */
-       if (!sb_any_quota_loaded(sb)) {
-               mutex_unlock(&dqopt->dqonoff_mutex);
+       if (!sb_any_quota_loaded(sb))
                return 0;
-       }
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
                toputinode[cnt] = NULL;
                if (type != -1 && cnt != type)
                dqopt->info[cnt].dqi_bgrace = 0;
                dqopt->ops[cnt] = NULL;
        }
-       mutex_unlock(&dqopt->dqonoff_mutex);
  
        /* Skip syncing and setting flags if quota files are hidden */
        if (dqopt->flags & DQUOT_QUOTA_SYS_FILE)
         * must also discard the blockdev buffers so that we see the
         * changes done by userspace on the next quotaon() */
        for (cnt = 0; cnt < MAXQUOTAS; cnt++)
-               if (toputinode[cnt]) {
-                       mutex_lock(&dqopt->dqonoff_mutex);
-                       /* If quota was reenabled in the meantime, we have
-                        * nothing to do */
-                       if (!sb_has_quota_loaded(sb, cnt)) {
-                               inode_lock(toputinode[cnt]);
-                               toputinode[cnt]->i_flags &= ~(S_IMMUTABLE |
+               /* This can happen when suspending quotas on remount-ro... */
+               if (toputinode[cnt] && !sb_has_quota_loaded(sb, cnt)) {
+                       inode_lock(toputinode[cnt]);
+                       toputinode[cnt]->i_flags &= ~(S_IMMUTABLE |
                                  S_NOATIME | S_NOQUOTA);
-                               truncate_inode_pages(&toputinode[cnt]->i_data,
-                                                    0);
-                               inode_unlock(toputinode[cnt]);
-                               mark_inode_dirty_sync(toputinode[cnt]);
-                       }
-                       mutex_unlock(&dqopt->dqonoff_mutex);
+                       truncate_inode_pages(&toputinode[cnt]->i_data, 0);
+                       inode_unlock(toputinode[cnt]);
+                       mark_inode_dirty_sync(toputinode[cnt]);
                }
        if (sb->s_bdev)
                invalidate_bdev(sb->s_bdev);
@@@ -2281,6 -2263,10 +2263,10 @@@ static int vfs_load_quota_inode(struct 
                error = -EINVAL;
                goto out_fmt;
        }
+       if (sb_has_quota_loaded(sb, type)) {
+               error = -EBUSY;
+               goto out_fmt;
+       }
  
        if (!(dqopt->flags & DQUOT_QUOTA_SYS_FILE)) {
                /* As we bypass the pagecache we must now flush all the
                sync_filesystem(sb);
                invalidate_bdev(sb->s_bdev);
        }
-       mutex_lock(&dqopt->dqonoff_mutex);
-       if (sb_has_quota_loaded(sb, type)) {
-               error = -EBUSY;
-               goto out_lock;
-       }
  
        if (!(dqopt->flags & DQUOT_QUOTA_SYS_FILE)) {
                /* We don't want quota and atime on quota files (deadlocks
        error = -EIO;
        dqopt->files[type] = igrab(inode);
        if (!dqopt->files[type])
-               goto out_lock;
+               goto out_file_flags;
        error = -EINVAL;
        if (!fmt->qf_ops->check_quota_file(sb, type))
                goto out_file_init;
        spin_unlock(&dq_state_lock);
  
        add_dquot_ref(sb, type);
-       mutex_unlock(&dqopt->dqonoff_mutex);
  
        return 0;
  
  out_file_init:
        dqopt->files[type] = NULL;
        iput(inode);
- out_lock:
+ out_file_flags:
        if (oldflags != -1) {
                inode_lock(inode);
                /* Set the flags back (in the case of accidental quotaon()
                inode->i_flags |= oldflags;
                inode_unlock(inode);
        }
-       mutex_unlock(&dqopt->dqonoff_mutex);
  out_fmt:
        put_quota_format(fmt);
  
@@@ -2371,15 -2350,16 +2350,16 @@@ int dquot_resume(struct super_block *sb
        int ret = 0, cnt;
        unsigned int flags;
  
+       /* s_umount should be held in exclusive mode */
+       if (WARN_ON_ONCE(down_read_trylock(&sb->s_umount)))
+               up_read(&sb->s_umount);
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
                if (type != -1 && cnt != type)
                        continue;
-               mutex_lock(&dqopt->dqonoff_mutex);
-               if (!sb_has_quota_suspended(sb, cnt)) {
-                       mutex_unlock(&dqopt->dqonoff_mutex);
+               if (!sb_has_quota_suspended(sb, cnt))
                        continue;
-               }
                inode = dqopt->files[cnt];
                dqopt->files[cnt] = NULL;
                spin_lock(&dq_state_lock);
                                                        cnt);
                dqopt->flags &= ~dquot_state_flag(DQUOT_STATE_FLAGS, cnt);
                spin_unlock(&dq_state_lock);
-               mutex_unlock(&dqopt->dqonoff_mutex);
  
                flags = dquot_generic_flag(flags, cnt);
                ret = vfs_load_quota_inode(inode, cnt,
  EXPORT_SYMBOL(dquot_resume);
  
  int dquot_quota_on(struct super_block *sb, int type, int format_id,
 -                 struct path *path)
 +                 const struct path *path)
  {
        int error = security_quota_on(path->dentry);
        if (error)
@@@ -2424,42 -2403,30 +2403,30 @@@ EXPORT_SYMBOL(dquot_quota_on)
  int dquot_enable(struct inode *inode, int type, int format_id,
                 unsigned int flags)
  {
-       int ret = 0;
        struct super_block *sb = inode->i_sb;
-       struct quota_info *dqopt = sb_dqopt(sb);
  
        /* Just unsuspend quotas? */
        BUG_ON(flags & DQUOT_SUSPENDED);
+       /* s_umount should be held in exclusive mode */
+       if (WARN_ON_ONCE(down_read_trylock(&sb->s_umount)))
+               up_read(&sb->s_umount);
  
        if (!flags)
                return 0;
        /* Just updating flags needed? */
        if (sb_has_quota_loaded(sb, type)) {
-               mutex_lock(&dqopt->dqonoff_mutex);
-               /* Now do a reliable test... */
-               if (!sb_has_quota_loaded(sb, type)) {
-                       mutex_unlock(&dqopt->dqonoff_mutex);
-                       goto load_quota;
-               }
                if (flags & DQUOT_USAGE_ENABLED &&
-                   sb_has_quota_usage_enabled(sb, type)) {
-                       ret = -EBUSY;
-                       goto out_lock;
-               }
+                   sb_has_quota_usage_enabled(sb, type))
+                       return -EBUSY;
                if (flags & DQUOT_LIMITS_ENABLED &&
-                   sb_has_quota_limits_enabled(sb, type)) {
-                       ret = -EBUSY;
-                       goto out_lock;
-               }
+                   sb_has_quota_limits_enabled(sb, type))
+                       return -EBUSY;
                spin_lock(&dq_state_lock);
                sb_dqopt(sb)->flags |= dquot_state_flag(flags, type);
                spin_unlock(&dq_state_lock);
- out_lock:
-               mutex_unlock(&dqopt->dqonoff_mutex);
-               return ret;
+               return 0;
        }
  
- load_quota:
        return vfs_load_quota_inode(inode, type, format_id, flags);
  }
  EXPORT_SYMBOL(dquot_enable);
@@@ -2751,7 -2718,6 +2718,6 @@@ int dquot_get_state(struct super_block 
        struct quota_info *dqopt = sb_dqopt(sb);
        int type;
    
-       mutex_lock(&sb_dqopt(sb)->dqonoff_mutex);
        memset(state, 0, sizeof(*state));
        for (type = 0; type < MAXQUOTAS; type++) {
                if (!sb_has_quota_active(sb, type))
                tstate->nextents = 1;   /* We don't know... */
                spin_unlock(&dq_data_lock);
        }
-       mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
        return 0;
  }
  EXPORT_SYMBOL(dquot_get_state);
@@@ -2787,18 -2752,13 +2752,13 @@@ int dquot_set_dqinfo(struct super_bloc
        if ((ii->i_fieldmask & QC_WARNS_MASK) ||
            (ii->i_fieldmask & QC_RT_SPC_TIMER))
                return -EINVAL;
-       mutex_lock(&sb_dqopt(sb)->dqonoff_mutex);
-       if (!sb_has_quota_active(sb, type)) {
-               err = -ESRCH;
-               goto out;
-       }
+       if (!sb_has_quota_active(sb, type))
+               return -ESRCH;
        mi = sb_dqopt(sb)->info + type;
        if (ii->i_fieldmask & QC_FLAGS) {
                if ((ii->i_flags & QCI_ROOT_SQUASH &&
-                    mi->dqi_format->qf_fmt_id != QFMT_VFS_OLD)) {
-                       err = -EINVAL;
-                       goto out;
-               }
+                    mi->dqi_format->qf_fmt_id != QFMT_VFS_OLD))
+                       return -EINVAL;
        }
        spin_lock(&dq_data_lock);
        if (ii->i_fieldmask & QC_SPC_TIMER)
        mark_info_dirty(sb, type);
        /* Force write to disk */
        sb->dq_op->write_info(sb, type);
- out:
-       mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
        return err;
  }
  EXPORT_SYMBOL(dquot_set_dqinfo);
diff --combined fs/quota/quota.c
index 5acd0c4769afa878f4435205cccb68897b81b035,413c36cca462db9e69fb83709407b1bc9de20dac..07e08c7d05cae23d92ab891cb384e5dda90509df
@@@ -80,7 -80,7 +80,7 @@@ unsigned int qtype_enforce_flag(int typ
  }
  
  static int quota_quotaon(struct super_block *sb, int type, qid_t id,
 -                       struct path *path)
 +                       const struct path *path)
  {
        if (!sb->s_qcop->quota_on && !sb->s_qcop->quota_enable)
                return -ENOSYS;
@@@ -104,13 -104,9 +104,9 @@@ static int quota_getfmt(struct super_bl
  {
        __u32 fmt;
  
-       mutex_lock(&sb_dqopt(sb)->dqonoff_mutex);
-       if (!sb_has_quota_active(sb, type)) {
-               mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
+       if (!sb_has_quota_active(sb, type))
                return -ESRCH;
-       }
        fmt = sb_dqopt(sb)->info[type].dqi_format->qf_fmt_id;
-       mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
        if (copy_to_user(addr, &fmt, sizeof(fmt)))
                return -EFAULT;
        return 0;
@@@ -700,7 -696,7 +696,7 @@@ static int quota_rmxquota(struct super_
  
  /* Copy parameters and call proper function */
  static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,
 -                     void __user *addr, struct path *path)
 +                     void __user *addr, const struct path *path)
  {
        int ret;
  
@@@ -789,9 -785,14 +785,14 @@@ static int quotactl_cmd_write(int cmd
        }
        return 1;
  }
  #endif /* CONFIG_BLOCK */
  
+ /* Return true if quotactl command is manipulating quota on/off state */
+ static bool quotactl_cmd_onoff(int cmd)
+ {
+       return (cmd == Q_QUOTAON) || (cmd == Q_QUOTAOFF);
+ }
  /*
   * look up a superblock on which quota ops will be performed
   * - use the name of a block device to find the superblock thereon
@@@ -809,7 -810,9 +810,9 @@@ static struct super_block *quotactl_blo
        putname(tmp);
        if (IS_ERR(bdev))
                return ERR_CAST(bdev);
-       if (quotactl_cmd_write(cmd))
+       if (quotactl_cmd_onoff(cmd))
+               sb = get_super_exclusive_thawed(bdev);
+       else if (quotactl_cmd_write(cmd))
                sb = get_super_thawed(bdev);
        else
                sb = get_super(bdev);
@@@ -872,7 -875,10 +875,10 @@@ SYSCALL_DEFINE4(quotactl, unsigned int
  
        ret = do_quotactl(sb, type, cmds, id, addr, pathp);
  
-       drop_super(sb);
+       if (!quotactl_cmd_onoff(cmds))
+               drop_super(sb);
+       else
+               drop_super_exclusive(sb);
  out:
        if (pathp && !IS_ERR(pathp))
                path_put(pathp);
diff --combined include/linux/fs.h
index e6e4146bf9ae5ee9def7da466f369127895713df,d04cfdefcd110c11ee00e083be05fa8af34f45e8..2ba074328894cea30d6273a574417d789fae271d
@@@ -28,6 -28,7 +28,6 @@@
  #include <linux/uidgid.h>
  #include <linux/lockdep.h>
  #include <linux/percpu-rwsem.h>
 -#include <linux/blk_types.h>
  #include <linux/workqueue.h>
  #include <linux/percpu-rwsem.h>
  #include <linux/delayed_call.h>
@@@ -37,7 -38,6 +37,7 @@@
  
  struct backing_dev_info;
  struct bdi_writeback;
 +struct bio;
  struct export_operations;
  struct hd_geometry;
  struct iovec;
@@@ -151,6 -151,58 +151,6 @@@ typedef int (dio_iodone_t)(struct kioc
   */
  #define CHECK_IOVEC_ONLY -1
  
 -/*
 - * The below are the various read and write flags that we support. Some of
 - * them include behavioral modifiers that send information down to the
 - * block layer and IO scheduler. They should be used along with a req_op.
 - * Terminology:
 - *
 - *    The block layer uses device plugging to defer IO a little bit, in
 - *    the hope that we will see more IO very shortly. This increases
 - *    coalescing of adjacent IO and thus reduces the number of IOs we
 - *    have to send to the device. It also allows for better queuing,
 - *    if the IO isn't mergeable. If the caller is going to be waiting
 - *    for the IO, then he must ensure that the device is unplugged so
 - *    that the IO is dispatched to the driver.
 - *
 - *    All IO is handled async in Linux. This is fine for background
 - *    writes, but for reads or writes that someone waits for completion
 - *    on, we want to notify the block layer and IO scheduler so that they
 - *    know about it. That allows them to make better scheduling
 - *    decisions. So when the below references 'sync' and 'async', it
 - *    is referencing this priority hint.
 - *
 - * With that in mind, the available types are:
 - *
 - * READ                       A normal read operation. Device will be plugged.
 - * READ_SYNC          A synchronous read. Device is not plugged, caller can
 - *                    immediately wait on this read without caring about
 - *                    unplugging.
 - * WRITE              A normal async write. Device will be plugged.
 - * WRITE_SYNC         Synchronous write. Identical to WRITE, but passes down
 - *                    the hint that someone will be waiting on this IO
 - *                    shortly. The write equivalent of READ_SYNC.
 - * WRITE_ODIRECT      Special case write for O_DIRECT only.
 - * WRITE_FLUSH                Like WRITE_SYNC but with preceding cache flush.
 - * WRITE_FUA          Like WRITE_SYNC but data is guaranteed to be on
 - *                    non-volatile media on completion.
 - * WRITE_FLUSH_FUA    Combination of WRITE_FLUSH and FUA. The IO is preceded
 - *                    by a cache flush and data is guaranteed to be on
 - *                    non-volatile media on completion.
 - *
 - */
 -#define RW_MASK                       REQ_OP_WRITE
 -
 -#define READ                  REQ_OP_READ
 -#define WRITE                 REQ_OP_WRITE
 -
 -#define READ_SYNC             REQ_SYNC
 -#define WRITE_SYNC            (REQ_SYNC | REQ_NOIDLE)
 -#define WRITE_ODIRECT         REQ_SYNC
 -#define WRITE_FLUSH           (REQ_SYNC | REQ_NOIDLE | REQ_PREFLUSH)
 -#define WRITE_FUA             (REQ_SYNC | REQ_NOIDLE | REQ_FUA)
 -#define WRITE_FLUSH_FUA               (REQ_SYNC | REQ_NOIDLE | REQ_PREFLUSH | REQ_FUA)
 -
  /*
   * Attribute flags.  These should be or-ed together to figure out what
   * has been changed!
@@@ -543,7 -595,6 +543,7 @@@ is_uncached_acl(struct posix_acl *acl
  #define IOP_LOOKUP    0x0002
  #define IOP_NOFOLLOW  0x0004
  #define IOP_XATTR     0x0008
 +#define IOP_DEFAULT_READLINK  0x0010
  
  /*
   * Keep mostly read-only and often accessed (especially for
@@@ -1727,30 -1778,11 +1727,30 @@@ extern ssize_t vfs_writev(struct file *
                unsigned long, loff_t *, int);
  extern ssize_t vfs_copy_file_range(struct file *, loff_t , struct file *,
                                   loff_t, size_t, unsigned int);
 +extern int vfs_clone_file_prep_inodes(struct inode *inode_in, loff_t pos_in,
 +                                    struct inode *inode_out, loff_t pos_out,
 +                                    u64 *len, bool is_dedupe);
  extern int vfs_clone_file_range(struct file *file_in, loff_t pos_in,
                struct file *file_out, loff_t pos_out, u64 len);
 +extern int vfs_dedupe_file_range_compare(struct inode *src, loff_t srcoff,
 +                                       struct inode *dest, loff_t destoff,
 +                                       loff_t len, bool *is_same);
  extern int vfs_dedupe_file_range(struct file *file,
                                 struct file_dedupe_range *same);
  
 +static inline int do_clone_file_range(struct file *file_in, loff_t pos_in,
 +                                    struct file *file_out, loff_t pos_out,
 +                                    u64 len)
 +{
 +      int ret;
 +
 +      sb_start_write(file_inode(file_out)->i_sb);
 +      ret = vfs_clone_file_range(file_in, pos_in, file_out, pos_out, len);
 +      sb_end_write(file_inode(file_out)->i_sb);
 +
 +      return ret;
 +}
 +
  struct super_operations {
        struct inode *(*alloc_inode)(struct super_block *sb);
        void (*destroy_inode)(struct inode *);
@@@ -2091,11 -2123,11 +2091,11 @@@ extern int may_umount_tree(struct vfsmo
  extern int may_umount(struct vfsmount *);
  extern long do_mount(const char *, const char __user *,
                     const char *, unsigned long, void *);
 -extern struct vfsmount *collect_mounts(struct path *);
 +extern struct vfsmount *collect_mounts(const struct path *);
  extern void drop_collected_mounts(struct vfsmount *);
  extern int iterate_mounts(int (*)(struct vfsmount *, void *), void *,
                          struct vfsmount *);
 -extern int vfs_statfs(struct path *, struct kstatfs *);
 +extern int vfs_statfs(const struct path *, struct kstatfs *);
  extern int user_statfs(const char __user *, struct kstatfs *);
  extern int fd_statfs(int, struct kstatfs *);
  extern int vfs_ustat(dev_t, struct kstatfs *);
@@@ -2467,6 -2499,19 +2467,6 @@@ extern void make_bad_inode(struct inod
  extern bool is_bad_inode(struct inode *);
  
  #ifdef CONFIG_BLOCK
 -static inline bool op_is_write(unsigned int op)
 -{
 -      return op == REQ_OP_READ ? false : true;
 -}
 -
 -/*
 - * return data direction, READ or WRITE
 - */
 -static inline int bio_data_dir(struct bio *bio)
 -{
 -      return op_is_write(bio_op(bio)) ? WRITE : READ;
 -}
 -
  extern void check_disk_size_change(struct gendisk *disk,
                                   struct block_device *bdev);
  extern int revalidate_disk(struct gendisk *);
@@@ -2664,7 -2709,7 +2664,7 @@@ extern struct file * open_exec(const ch
   
  /* fs/dcache.c -- generic fs support functions */
  extern bool is_subdir(struct dentry *, struct dentry *);
 -extern bool path_is_under(struct path *, struct path *);
 +extern bool path_is_under(const struct path *, const struct path *);
  
  extern char *file_path(struct file *, char *, int);
  
@@@ -2737,6 -2782,7 +2737,6 @@@ static inline void remove_inode_hash(st
  extern void inode_sb_list_add(struct inode *inode);
  
  #ifdef CONFIG_BLOCK
 -extern blk_qc_t submit_bio(struct bio *);
  extern int bdev_read_only(struct block_device *);
  #endif
  extern int set_blocksize(struct block_device *, int);
@@@ -2868,6 -2914,7 +2868,6 @@@ extern int __page_symlink(struct inode 
  extern int page_symlink(struct inode *inode, const char *symname, int len);
  extern const struct inode_operations page_symlink_inode_operations;
  extern void kfree_link(void *);
 -extern int generic_readlink(struct dentry *, char __user *, int);
  extern void generic_fillattr(struct inode *, struct kstat *);
  int vfs_getattr_nosec(struct path *path, struct kstat *stat);
  extern int vfs_getattr(struct path *, struct kstat *);
@@@ -2888,7 -2935,6 +2888,7 @@@ extern int vfs_lstat(const char __user 
  extern int vfs_fstat(unsigned int, struct kstat *);
  extern int vfs_fstatat(int , const char __user *, struct kstat *, int);
  extern const char *vfs_get_link(struct dentry *, struct delayed_call *);
 +extern int vfs_readlink(struct dentry *, char __user *, int);
  
  extern int __generic_block_fiemap(struct inode *inode,
                                  struct fiemap_extent_info *fieinfo,
@@@ -2903,8 -2949,10 +2903,10 @@@ extern void put_filesystem(struct file_
  extern struct file_system_type *get_fs_type(const char *name);
  extern struct super_block *get_super(struct block_device *);
  extern struct super_block *get_super_thawed(struct block_device *);
+ extern struct super_block *get_super_exclusive_thawed(struct block_device *bdev);
  extern struct super_block *get_active_super(struct block_device *bdev);
  extern void drop_super(struct super_block *sb);
+ extern void drop_super_exclusive(struct super_block *sb);
  extern void iterate_supers(void (*)(struct super_block *, void *), void *);
  extern void iterate_supers_type(struct file_system_type *,
                                void (*)(struct super_block *, void *), void *);
diff --combined include/linux/quota.h
index 78a98821f9d0a98780e6129b6b1f4cc9c0fc4d80,b281d198ee5bc73fee718feec853b211017f1f46..3434eef2a5aad963d579670ed081b68db382239d
@@@ -431,7 -431,7 +431,7 @@@ struct qc_info 
  
  /* Operations handling requests from userspace */
  struct quotactl_ops {
 -      int (*quota_on)(struct super_block *, int, int, struct path *);
 +      int (*quota_on)(struct super_block *, int, int, const struct path *);
        int (*quota_off)(struct super_block *, int);
        int (*quota_enable)(struct super_block *, unsigned int);
        int (*quota_disable)(struct super_block *, unsigned int);
@@@ -520,7 -520,6 +520,6 @@@ static inline void quota_send_warning(s
  struct quota_info {
        unsigned int flags;                     /* Flags for diskquotas on this device */
        struct mutex dqio_mutex;                /* lock device while I/O in progress */
-       struct mutex dqonoff_mutex;             /* Serialize quotaon & quotaoff */
        struct inode *files[MAXQUOTAS];         /* inodes of quotafiles */
        struct mem_dqinfo info[MAXQUOTAS];      /* Information for each quota type */
        const struct quota_format_ops *ops[MAXQUOTAS];  /* Operations for each type */