f2fs: use mnt_{want,drop}_write_file in ioctl
authorChao Yu <yuchao0@huawei.com>
Mon, 9 May 2016 11:56:32 +0000 (19:56 +0800)
committerJaegeuk Kim <jaegeuk@kernel.org>
Wed, 11 May 2016 16:56:32 +0000 (09:56 -0700)
In interfaces of ioctl, mnt_{want,drop}_write_file should be used for:
- get exclusion against file system freezing which may used by lvm
  snapshot.
- do telling filesystem that a write is about to be performed on it, and
  make sure that the writes are permitted.

Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
fs/f2fs/file.c

index 3146129..2f8f225 100644 (file)
@@ -1307,20 +1307,16 @@ static int f2fs_ioc_setflags(struct file *filp, unsigned long arg)
        unsigned int oldflags;
        int ret;
 
+       if (!inode_owner_or_capable(inode))
+               return -EACCES;
+
+       if (get_user(flags, (int __user *)arg))
+               return -EFAULT;
+
        ret = mnt_want_write_file(filp);
        if (ret)
                return ret;
 
-       if (!inode_owner_or_capable(inode)) {
-               ret = -EACCES;
-               goto out;
-       }
-
-       if (get_user(flags, (int __user *)arg)) {
-               ret = -EFAULT;
-               goto out;
-       }
-
        flags = f2fs_mask_flags(inode->i_mode, flags);
 
        inode_lock(inode);
@@ -1363,18 +1359,22 @@ static int f2fs_ioc_start_atomic_write(struct file *filp)
        if (!inode_owner_or_capable(inode))
                return -EACCES;
 
+       ret = mnt_want_write_file(filp);
+       if (ret)
+               return ret;
+
        if (f2fs_is_atomic_file(inode))
-               return 0;
+               goto out;
 
        ret = f2fs_convert_inline_inode(inode);
        if (ret)
-               return ret;
+               goto out;
 
        set_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE);
        f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
 
        if (!get_dirty_pages(inode))
-               return 0;
+               goto out;
 
        f2fs_msg(F2FS_I_SB(inode)->sb, KERN_WARNING,
                "Unexpected flush for atomic writes: ino=%lu, npages=%u",
@@ -1382,6 +1382,8 @@ static int f2fs_ioc_start_atomic_write(struct file *filp)
        ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX);
        if (ret)
                clear_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE);
+out:
+       mnt_drop_write_file(filp);
        return ret;
 }
 
@@ -1393,13 +1395,13 @@ static int f2fs_ioc_commit_atomic_write(struct file *filp)
        if (!inode_owner_or_capable(inode))
                return -EACCES;
 
-       if (f2fs_is_volatile_file(inode))
-               return 0;
-
        ret = mnt_want_write_file(filp);
        if (ret)
                return ret;
 
+       if (f2fs_is_volatile_file(inode))
+               goto err_out;
+
        if (f2fs_is_atomic_file(inode)) {
                clear_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE);
                ret = commit_inmem_pages(inode);
@@ -1423,32 +1425,48 @@ static int f2fs_ioc_start_volatile_write(struct file *filp)
        if (!inode_owner_or_capable(inode))
                return -EACCES;
 
+       ret = mnt_want_write_file(filp);
+       if (ret)
+               return ret;
+
        if (f2fs_is_volatile_file(inode))
-               return 0;
+               goto out;
 
        ret = f2fs_convert_inline_inode(inode);
        if (ret)
-               return ret;
+               goto out;
 
        set_inode_flag(F2FS_I(inode), FI_VOLATILE_FILE);
        f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
-       return 0;
+out:
+       mnt_drop_write_file(filp);
+       return ret;
 }
 
 static int f2fs_ioc_release_volatile_write(struct file *filp)
 {
        struct inode *inode = file_inode(filp);
+       int ret;
 
        if (!inode_owner_or_capable(inode))
                return -EACCES;
 
+       ret = mnt_want_write_file(filp);
+       if (ret)
+               return ret;
+
        if (!f2fs_is_volatile_file(inode))
-               return 0;
+               goto out;
 
-       if (!f2fs_is_first_block_written(inode))
-               return truncate_partial_data_page(inode, 0, true);
+       if (!f2fs_is_first_block_written(inode)) {
+               ret = truncate_partial_data_page(inode, 0, true);
+               goto out;
+       }
 
-       return punch_hole(inode, 0, F2FS_BLKSIZE);
+       ret = punch_hole(inode, 0, F2FS_BLKSIZE);
+out:
+       mnt_drop_write_file(filp);
+       return ret;
 }
 
 static int f2fs_ioc_abort_volatile_write(struct file *filp)
@@ -1481,6 +1499,7 @@ static int f2fs_ioc_shutdown(struct file *filp, unsigned long arg)
        struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
        struct super_block *sb = sbi->sb;
        __u32 in;
+       int ret;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
@@ -1488,6 +1507,10 @@ static int f2fs_ioc_shutdown(struct file *filp, unsigned long arg)
        if (get_user(in, (__u32 __user *)arg))
                return -EFAULT;
 
+       ret = mnt_want_write_file(filp);
+       if (ret)
+               return ret;
+
        switch (in) {
        case F2FS_GOING_DOWN_FULLSYNC:
                sb = freeze_bdev(sb->s_bdev);
@@ -1509,10 +1532,13 @@ static int f2fs_ioc_shutdown(struct file *filp, unsigned long arg)
                f2fs_stop_checkpoint(sbi);
                break;
        default:
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out;
        }
        f2fs_update_time(sbi, REQ_TIME);
-       return 0;
+out:
+       mnt_drop_write_file(filp);
+       return ret;
 }
 
 static int f2fs_ioc_fitrim(struct file *filp, unsigned long arg)
@@ -1533,9 +1559,14 @@ static int f2fs_ioc_fitrim(struct file *filp, unsigned long arg)
                                sizeof(range)))
                return -EFAULT;
 
+       ret = mnt_want_write_file(filp);
+       if (ret)
+               return ret;
+
        range.minlen = max((unsigned int)range.minlen,
                                q->limits.discard_granularity);
        ret = f2fs_trim_fs(F2FS_SB(sb), &range);
+       mnt_drop_write_file(filp);
        if (ret < 0)
                return ret;
 
@@ -1560,13 +1591,21 @@ static int f2fs_ioc_set_encryption_policy(struct file *filp, unsigned long arg)
 {
        struct fscrypt_policy policy;
        struct inode *inode = file_inode(filp);
+       int ret;
 
        if (copy_from_user(&policy, (struct fscrypt_policy __user *)arg,
                                                        sizeof(policy)))
                return -EFAULT;
 
+       ret = mnt_want_write_file(filp);
+       if (ret)
+               return ret;
+
        f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
-       return fscrypt_process_policy(inode, &policy);
+       ret = fscrypt_process_policy(inode, &policy);
+
+       mnt_drop_write_file(filp);
+       return ret;
 }
 
 static int f2fs_ioc_get_encryption_policy(struct file *filp, unsigned long arg)
@@ -1623,6 +1662,7 @@ static int f2fs_ioc_gc(struct file *filp, unsigned long arg)
        struct inode *inode = file_inode(filp);
        struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
        __u32 sync;
+       int ret;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
@@ -1633,20 +1673,30 @@ static int f2fs_ioc_gc(struct file *filp, unsigned long arg)
        if (f2fs_readonly(sbi->sb))
                return -EROFS;
 
+       ret = mnt_want_write_file(filp);
+       if (ret)
+               return ret;
+
        if (!sync) {
-               if (!mutex_trylock(&sbi->gc_mutex))
-                       return -EBUSY;
+               if (!mutex_trylock(&sbi->gc_mutex)) {
+                       ret = -EBUSY;
+                       goto out;
+               }
        } else {
                mutex_lock(&sbi->gc_mutex);
        }
 
-       return f2fs_gc(sbi, sync);
+       ret = f2fs_gc(sbi, sync);
+out:
+       mnt_drop_write_file(filp);
+       return ret;
 }
 
 static int f2fs_ioc_write_checkpoint(struct file *filp, unsigned long arg)
 {
        struct inode *inode = file_inode(filp);
        struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+       int ret;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
@@ -1654,7 +1704,14 @@ static int f2fs_ioc_write_checkpoint(struct file *filp, unsigned long arg)
        if (f2fs_readonly(sbi->sb))
                return -EROFS;
 
-       return f2fs_sync_fs(sbi->sb, 1);
+       ret = mnt_want_write_file(filp);
+       if (ret)
+               return ret;
+
+       ret = f2fs_sync_fs(sbi->sb, 1);
+
+       mnt_drop_write_file(filp);
+       return ret;
 }
 
 static int f2fs_defragment_range(struct f2fs_sb_info *sbi,