|
21 | 21 | #include <linux/uuid.h>
|
22 | 22 | #include <linux/file.h>
|
23 | 23 | #include <linux/nls.h>
|
| 24 | +#include <linux/sched/signal.h> |
24 | 25 |
|
25 | 26 | #include "f2fs.h"
|
26 | 27 | #include "node.h"
|
@@ -3759,6 +3760,193 @@ static int f2fs_reserve_compress_blocks(struct file *filp, unsigned long arg)
|
3759 | 3760 | return ret;
|
3760 | 3761 | }
|
3761 | 3762 |
|
| 3763 | +static int f2fs_secure_erase(struct block_device *bdev, struct inode *inode, |
| 3764 | + pgoff_t off, block_t block, block_t len, u32 flags) |
| 3765 | +{ |
| 3766 | + struct request_queue *q = bdev_get_queue(bdev); |
| 3767 | + sector_t sector = SECTOR_FROM_BLOCK(block); |
| 3768 | + sector_t nr_sects = SECTOR_FROM_BLOCK(len); |
| 3769 | + int ret = 0; |
| 3770 | + |
| 3771 | + if (!q) |
| 3772 | + return -ENXIO; |
| 3773 | + |
| 3774 | + if (flags & F2FS_TRIM_FILE_DISCARD) |
| 3775 | + ret = blkdev_issue_discard(bdev, sector, nr_sects, GFP_NOFS, |
| 3776 | + blk_queue_secure_erase(q) ? |
| 3777 | + BLKDEV_DISCARD_SECURE : 0); |
| 3778 | + |
| 3779 | + if (!ret && (flags & F2FS_TRIM_FILE_ZEROOUT)) { |
| 3780 | + if (IS_ENCRYPTED(inode)) |
| 3781 | + ret = fscrypt_zeroout_range(inode, off, block, len); |
| 3782 | + else |
| 3783 | + ret = blkdev_issue_zeroout(bdev, sector, nr_sects, |
| 3784 | + GFP_NOFS, 0); |
| 3785 | + } |
| 3786 | + |
| 3787 | + return ret; |
| 3788 | +} |
| 3789 | + |
| 3790 | +static int f2fs_sec_trim_file(struct file *filp, unsigned long arg) |
| 3791 | +{ |
| 3792 | + struct inode *inode = file_inode(filp); |
| 3793 | + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); |
| 3794 | + struct address_space *mapping = inode->i_mapping; |
| 3795 | + struct block_device *prev_bdev = NULL; |
| 3796 | + struct f2fs_sectrim_range range; |
| 3797 | + pgoff_t index, pg_end, prev_index = 0; |
| 3798 | + block_t prev_block = 0, len = 0; |
| 3799 | + loff_t end_addr; |
| 3800 | + bool to_end = false; |
| 3801 | + int ret = 0; |
| 3802 | + |
| 3803 | + if (!(filp->f_mode & FMODE_WRITE)) |
| 3804 | + return -EBADF; |
| 3805 | + |
| 3806 | + if (copy_from_user(&range, (struct f2fs_sectrim_range __user *)arg, |
| 3807 | + sizeof(range))) |
| 3808 | + return -EFAULT; |
| 3809 | + |
| 3810 | + if (range.flags == 0 || (range.flags & ~F2FS_TRIM_FILE_MASK) || |
| 3811 | + !S_ISREG(inode->i_mode)) |
| 3812 | + return -EINVAL; |
| 3813 | + |
| 3814 | + if (((range.flags & F2FS_TRIM_FILE_DISCARD) && |
| 3815 | + !f2fs_hw_support_discard(sbi)) || |
| 3816 | + ((range.flags & F2FS_TRIM_FILE_ZEROOUT) && |
| 3817 | + IS_ENCRYPTED(inode) && f2fs_is_multi_device(sbi))) |
| 3818 | + return -EOPNOTSUPP; |
| 3819 | + |
| 3820 | + file_start_write(filp); |
| 3821 | + inode_lock(inode); |
| 3822 | + |
| 3823 | + if (f2fs_is_atomic_file(inode) || f2fs_compressed_file(inode) || |
| 3824 | + range.start >= inode->i_size) { |
| 3825 | + ret = -EINVAL; |
| 3826 | + goto err; |
| 3827 | + } |
| 3828 | + |
| 3829 | + if (range.len == 0) |
| 3830 | + goto err; |
| 3831 | + |
| 3832 | + if (inode->i_size - range.start > range.len) { |
| 3833 | + end_addr = range.start + range.len; |
| 3834 | + } else { |
| 3835 | + end_addr = range.len == (u64)-1 ? |
| 3836 | + sbi->sb->s_maxbytes : inode->i_size; |
| 3837 | + to_end = true; |
| 3838 | + } |
| 3839 | + |
| 3840 | + if (!IS_ALIGNED(range.start, F2FS_BLKSIZE) || |
| 3841 | + (!to_end && !IS_ALIGNED(end_addr, F2FS_BLKSIZE))) { |
| 3842 | + ret = -EINVAL; |
| 3843 | + goto err; |
| 3844 | + } |
| 3845 | + |
| 3846 | + index = F2FS_BYTES_TO_BLK(range.start); |
| 3847 | + pg_end = DIV_ROUND_UP(end_addr, F2FS_BLKSIZE); |
| 3848 | + |
| 3849 | + ret = f2fs_convert_inline_inode(inode); |
| 3850 | + if (ret) |
| 3851 | + goto err; |
| 3852 | + |
| 3853 | + down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); |
| 3854 | + down_write(&F2FS_I(inode)->i_mmap_sem); |
| 3855 | + |
| 3856 | + ret = filemap_write_and_wait_range(mapping, range.start, |
| 3857 | + to_end ? LLONG_MAX : end_addr - 1); |
| 3858 | + if (ret) |
| 3859 | + goto out; |
| 3860 | + |
| 3861 | + truncate_inode_pages_range(mapping, range.start, |
| 3862 | + to_end ? -1 : end_addr - 1); |
| 3863 | + |
| 3864 | + while (index < pg_end) { |
| 3865 | + struct dnode_of_data dn; |
| 3866 | + pgoff_t end_offset, count; |
| 3867 | + int i; |
| 3868 | + |
| 3869 | + set_new_dnode(&dn, inode, NULL, NULL, 0); |
| 3870 | + ret = f2fs_get_dnode_of_data(&dn, index, LOOKUP_NODE); |
| 3871 | + if (ret) { |
| 3872 | + if (ret == -ENOENT) { |
| 3873 | + index = f2fs_get_next_page_offset(&dn, index); |
| 3874 | + continue; |
| 3875 | + } |
| 3876 | + goto out; |
| 3877 | + } |
| 3878 | + |
| 3879 | + end_offset = ADDRS_PER_PAGE(dn.node_page, inode); |
| 3880 | + count = min(end_offset - dn.ofs_in_node, pg_end - index); |
| 3881 | + for (i = 0; i < count; i++, index++, dn.ofs_in_node++) { |
| 3882 | + struct block_device *cur_bdev; |
| 3883 | + block_t blkaddr = f2fs_data_blkaddr(&dn); |
| 3884 | + |
| 3885 | + if (!__is_valid_data_blkaddr(blkaddr)) |
| 3886 | + continue; |
| 3887 | + |
| 3888 | + if (!f2fs_is_valid_blkaddr(sbi, blkaddr, |
| 3889 | + DATA_GENERIC_ENHANCE)) { |
| 3890 | + ret = -EFSCORRUPTED; |
| 3891 | + f2fs_put_dnode(&dn); |
| 3892 | + goto out; |
| 3893 | + } |
| 3894 | + |
| 3895 | + cur_bdev = f2fs_target_device(sbi, blkaddr, NULL); |
| 3896 | + if (f2fs_is_multi_device(sbi)) { |
| 3897 | + int di = f2fs_target_device_index(sbi, blkaddr); |
| 3898 | + |
| 3899 | + blkaddr -= FDEV(di).start_blk; |
| 3900 | + } |
| 3901 | + |
| 3902 | + if (len) { |
| 3903 | + if (prev_bdev == cur_bdev && |
| 3904 | + index == prev_index + len && |
| 3905 | + blkaddr == prev_block + len) { |
| 3906 | + len++; |
| 3907 | + } else { |
| 3908 | + ret = f2fs_secure_erase(prev_bdev, |
| 3909 | + inode, prev_index, prev_block, |
| 3910 | + len, range.flags); |
| 3911 | + if (ret) { |
| 3912 | + f2fs_put_dnode(&dn); |
| 3913 | + goto out; |
| 3914 | + } |
| 3915 | + |
| 3916 | + len = 0; |
| 3917 | + } |
| 3918 | + } |
| 3919 | + |
| 3920 | + if (!len) { |
| 3921 | + prev_bdev = cur_bdev; |
| 3922 | + prev_index = index; |
| 3923 | + prev_block = blkaddr; |
| 3924 | + len = 1; |
| 3925 | + } |
| 3926 | + } |
| 3927 | + |
| 3928 | + f2fs_put_dnode(&dn); |
| 3929 | + |
| 3930 | + if (fatal_signal_pending(current)) { |
| 3931 | + ret = -EINTR; |
| 3932 | + goto out; |
| 3933 | + } |
| 3934 | + cond_resched(); |
| 3935 | + } |
| 3936 | + |
| 3937 | + if (len) |
| 3938 | + ret = f2fs_secure_erase(prev_bdev, inode, prev_index, |
| 3939 | + prev_block, len, range.flags); |
| 3940 | +out: |
| 3941 | + up_write(&F2FS_I(inode)->i_mmap_sem); |
| 3942 | + up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); |
| 3943 | +err: |
| 3944 | + inode_unlock(inode); |
| 3945 | + file_end_write(filp); |
| 3946 | + |
| 3947 | + return ret; |
| 3948 | +} |
| 3949 | + |
3762 | 3950 | long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
3763 | 3951 | {
|
3764 | 3952 | if (unlikely(f2fs_cp_error(F2FS_I_SB(file_inode(filp)))))
|
@@ -3845,6 +4033,8 @@ long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
3845 | 4033 | return f2fs_release_compress_blocks(filp, arg);
|
3846 | 4034 | case F2FS_IOC_RESERVE_COMPRESS_BLOCKS:
|
3847 | 4035 | return f2fs_reserve_compress_blocks(filp, arg);
|
| 4036 | + case F2FS_IOC_SEC_TRIM_FILE: |
| 4037 | + return f2fs_sec_trim_file(filp, arg); |
3848 | 4038 | default:
|
3849 | 4039 | return -ENOTTY;
|
3850 | 4040 | }
|
@@ -4014,6 +4204,7 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
4014 | 4204 | case F2FS_IOC_GET_COMPRESS_BLOCKS:
|
4015 | 4205 | case F2FS_IOC_RELEASE_COMPRESS_BLOCKS:
|
4016 | 4206 | case F2FS_IOC_RESERVE_COMPRESS_BLOCKS:
|
| 4207 | + case F2FS_IOC_SEC_TRIM_FILE: |
4017 | 4208 | break;
|
4018 | 4209 | default:
|
4019 | 4210 | return -ENOIOCTLCMD;
|
|
0 commit comments