Revert "block: don't call into the driver for BLKROSET"
[platform/kernel/linux-rpi.git] / fs / exfat / file.c
index f783cf3..d890fd3 100644 (file)
@@ -4,6 +4,7 @@
  */
 
 #include <linux/slab.h>
+#include <linux/compat.h>
 #include <linux/cred.h>
 #include <linux/buffer_head.h>
 #include <linux/blkdev.h>
@@ -109,8 +110,7 @@ int __exfat_truncate(struct inode *inode, loff_t new_size)
        exfat_set_volume_dirty(sb);
 
        num_clusters_new = EXFAT_B_TO_CLU_ROUND_UP(i_size_read(inode), sbi);
-       num_clusters_phys =
-               EXFAT_B_TO_CLU_ROUND_UP(EXFAT_I(inode)->i_size_ondisk, sbi);
+       num_clusters_phys = EXFAT_B_TO_CLU_ROUND_UP(ei->i_size_ondisk, sbi);
 
        exfat_chain_set(&clu, ei->start_clu, num_clusters_phys, ei->flags);
 
@@ -227,12 +227,13 @@ void exfat_truncate(struct inode *inode, loff_t size)
 {
        struct super_block *sb = inode->i_sb;
        struct exfat_sb_info *sbi = EXFAT_SB(sb);
+       struct exfat_inode_info *ei = EXFAT_I(inode);
        unsigned int blocksize = i_blocksize(inode);
        loff_t aligned_size;
        int err;
 
        mutex_lock(&sbi->s_lock);
-       if (EXFAT_I(inode)->start_clu == 0) {
+       if (ei->start_clu == 0) {
                /*
                 * Empty start_clu != ~0 (not allocated)
                 */
@@ -250,8 +251,8 @@ void exfat_truncate(struct inode *inode, loff_t size)
        else
                mark_inode_dirty(inode);
 
-       inode->i_blocks = ((i_size_read(inode) + (sbi->cluster_size - 1)) &
-                       ~(sbi->cluster_size - 1)) >> inode->i_blkbits;
+       inode->i_blocks = round_up(i_size_read(inode), sbi->cluster_size) >>
+                               inode->i_blkbits;
 write_size:
        aligned_size = i_size_read(inode);
        if (aligned_size & (blocksize - 1)) {
@@ -259,11 +260,11 @@ write_size:
                aligned_size++;
        }
 
-       if (EXFAT_I(inode)->i_size_ondisk > i_size_read(inode))
-               EXFAT_I(inode)->i_size_ondisk = aligned_size;
+       if (ei->i_size_ondisk > i_size_read(inode))
+               ei->i_size_ondisk = aligned_size;
 
-       if (EXFAT_I(inode)->i_size_aligned > i_size_read(inode))
-               EXFAT_I(inode)->i_size_aligned = aligned_size;
+       if (ei->i_size_aligned > i_size_read(inode))
+               ei->i_size_aligned = aligned_size;
        mutex_unlock(&sbi->s_lock);
 }
 
@@ -350,6 +351,54 @@ out:
        return error;
 }
 
+static int exfat_ioctl_fitrim(struct inode *inode, unsigned long arg)
+{
+       struct request_queue *q = bdev_get_queue(inode->i_sb->s_bdev);
+       struct fstrim_range range;
+       int ret = 0;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       if (!blk_queue_discard(q))
+               return -EOPNOTSUPP;
+
+       if (copy_from_user(&range, (struct fstrim_range __user *)arg, sizeof(range)))
+               return -EFAULT;
+
+       range.minlen = max_t(unsigned int, range.minlen,
+                               q->limits.discard_granularity);
+
+       ret = exfat_trim_fs(inode, &range);
+       if (ret < 0)
+               return ret;
+
+       if (copy_to_user((struct fstrim_range __user *)arg, &range, sizeof(range)))
+               return -EFAULT;
+
+       return 0;
+}
+
+long exfat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+       struct inode *inode = file_inode(filp);
+
+       switch (cmd) {
+       case FITRIM:
+               return exfat_ioctl_fitrim(inode, arg);
+       default:
+               return -ENOTTY;
+       }
+}
+
+#ifdef CONFIG_COMPAT
+long exfat_compat_ioctl(struct file *filp, unsigned int cmd,
+                               unsigned long arg)
+{
+       return exfat_ioctl(filp, cmd, (unsigned long)compat_ptr(arg));
+}
+#endif
+
 int exfat_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync)
 {
        struct inode *inode = filp->f_mapping->host;
@@ -370,6 +419,10 @@ const struct file_operations exfat_file_operations = {
        .llseek         = generic_file_llseek,
        .read_iter      = generic_file_read_iter,
        .write_iter     = generic_file_write_iter,
+       .unlocked_ioctl = exfat_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl = exfat_compat_ioctl,
+#endif
        .mmap           = generic_file_mmap,
        .fsync          = exfat_file_fsync,
        .splice_read    = generic_file_splice_read,