diff options
Diffstat (limited to 'fs/ext4/ioctl.c')
-rw-r--r-- | fs/ext4/ioctl.c | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index 5444d49cbf09..0b7f316fd30f 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c | |||
@@ -745,6 +745,74 @@ static void ext4_fill_fsxattr(struct inode *inode, struct fsxattr *fa) | |||
745 | fa->fsx_projid = from_kprojid(&init_user_ns, ei->i_projid); | 745 | fa->fsx_projid = from_kprojid(&init_user_ns, ei->i_projid); |
746 | } | 746 | } |
747 | 747 | ||
748 | /* copied from fs/ioctl.c */ | ||
749 | static int fiemap_check_ranges(struct super_block *sb, | ||
750 | u64 start, u64 len, u64 *new_len) | ||
751 | { | ||
752 | u64 maxbytes = (u64) sb->s_maxbytes; | ||
753 | |||
754 | *new_len = len; | ||
755 | |||
756 | if (len == 0) | ||
757 | return -EINVAL; | ||
758 | |||
759 | if (start > maxbytes) | ||
760 | return -EFBIG; | ||
761 | |||
762 | /* | ||
763 | * Shrink request scope to what the fs can actually handle. | ||
764 | */ | ||
765 | if (len > maxbytes || (maxbytes - len) < start) | ||
766 | *new_len = maxbytes - start; | ||
767 | |||
768 | return 0; | ||
769 | } | ||
770 | |||
771 | /* So that the fiemap access checks can't overflow on 32 bit machines. */ | ||
772 | #define FIEMAP_MAX_EXTENTS (UINT_MAX / sizeof(struct fiemap_extent)) | ||
773 | |||
774 | static int ext4_ioctl_get_es_cache(struct file *filp, unsigned long arg) | ||
775 | { | ||
776 | struct fiemap fiemap; | ||
777 | struct fiemap __user *ufiemap = (struct fiemap __user *) arg; | ||
778 | struct fiemap_extent_info fieinfo = { 0, }; | ||
779 | struct inode *inode = file_inode(filp); | ||
780 | struct super_block *sb = inode->i_sb; | ||
781 | u64 len; | ||
782 | int error; | ||
783 | |||
784 | if (copy_from_user(&fiemap, ufiemap, sizeof(fiemap))) | ||
785 | return -EFAULT; | ||
786 | |||
787 | if (fiemap.fm_extent_count > FIEMAP_MAX_EXTENTS) | ||
788 | return -EINVAL; | ||
789 | |||
790 | error = fiemap_check_ranges(sb, fiemap.fm_start, fiemap.fm_length, | ||
791 | &len); | ||
792 | if (error) | ||
793 | return error; | ||
794 | |||
795 | fieinfo.fi_flags = fiemap.fm_flags; | ||
796 | fieinfo.fi_extents_max = fiemap.fm_extent_count; | ||
797 | fieinfo.fi_extents_start = ufiemap->fm_extents; | ||
798 | |||
799 | if (fiemap.fm_extent_count != 0 && | ||
800 | !access_ok(fieinfo.fi_extents_start, | ||
801 | fieinfo.fi_extents_max * sizeof(struct fiemap_extent))) | ||
802 | return -EFAULT; | ||
803 | |||
804 | if (fieinfo.fi_flags & FIEMAP_FLAG_SYNC) | ||
805 | filemap_write_and_wait(inode->i_mapping); | ||
806 | |||
807 | error = ext4_get_es_cache(inode, &fieinfo, fiemap.fm_start, len); | ||
808 | fiemap.fm_flags = fieinfo.fi_flags; | ||
809 | fiemap.fm_mapped_extents = fieinfo.fi_extents_mapped; | ||
810 | if (copy_to_user(ufiemap, &fiemap, sizeof(fiemap))) | ||
811 | error = -EFAULT; | ||
812 | |||
813 | return error; | ||
814 | } | ||
815 | |||
748 | long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | 816 | long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) |
749 | { | 817 | { |
750 | struct inode *inode = file_inode(filp); | 818 | struct inode *inode = file_inode(filp); |
@@ -1142,6 +1210,33 @@ resizefs_out: | |||
1142 | return -EOPNOTSUPP; | 1210 | return -EOPNOTSUPP; |
1143 | return fscrypt_ioctl_get_key_status(filp, (void __user *)arg); | 1211 | return fscrypt_ioctl_get_key_status(filp, (void __user *)arg); |
1144 | 1212 | ||
1213 | case EXT4_IOC_CLEAR_ES_CACHE: | ||
1214 | { | ||
1215 | if (!inode_owner_or_capable(inode)) | ||
1216 | return -EACCES; | ||
1217 | ext4_clear_inode_es(inode); | ||
1218 | return 0; | ||
1219 | } | ||
1220 | |||
1221 | case EXT4_IOC_GETSTATE: | ||
1222 | { | ||
1223 | __u32 state = 0; | ||
1224 | |||
1225 | if (ext4_test_inode_state(inode, EXT4_STATE_EXT_PRECACHED)) | ||
1226 | state |= EXT4_STATE_FLAG_EXT_PRECACHED; | ||
1227 | if (ext4_test_inode_state(inode, EXT4_STATE_NEW)) | ||
1228 | state |= EXT4_STATE_FLAG_NEW; | ||
1229 | if (ext4_test_inode_state(inode, EXT4_STATE_NEWENTRY)) | ||
1230 | state |= EXT4_STATE_FLAG_NEWENTRY; | ||
1231 | if (ext4_test_inode_state(inode, EXT4_STATE_DA_ALLOC_CLOSE)) | ||
1232 | state |= EXT4_STATE_FLAG_DA_ALLOC_CLOSE; | ||
1233 | |||
1234 | return put_user(state, (__u32 __user *) arg); | ||
1235 | } | ||
1236 | |||
1237 | case EXT4_IOC_GET_ES_CACHE: | ||
1238 | return ext4_ioctl_get_es_cache(filp, arg); | ||
1239 | |||
1145 | case EXT4_IOC_FSGETXATTR: | 1240 | case EXT4_IOC_FSGETXATTR: |
1146 | { | 1241 | { |
1147 | struct fsxattr fa; | 1242 | struct fsxattr fa; |
@@ -1278,6 +1373,9 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
1278 | case FS_IOC_GETFSMAP: | 1373 | case FS_IOC_GETFSMAP: |
1279 | case FS_IOC_ENABLE_VERITY: | 1374 | case FS_IOC_ENABLE_VERITY: |
1280 | case FS_IOC_MEASURE_VERITY: | 1375 | case FS_IOC_MEASURE_VERITY: |
1376 | case EXT4_IOC_CLEAR_ES_CACHE: | ||
1377 | case EXT4_IOC_GETSTATE: | ||
1378 | case EXT4_IOC_GET_ES_CACHE: | ||
1281 | break; | 1379 | break; |
1282 | default: | 1380 | default: |
1283 | return -ENOIOCTLCMD; | 1381 | return -ENOIOCTLCMD; |