diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2013-03-20 10:42:10 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2013-04-09 14:12:56 -0400 |
commit | 72ec35163f9f728ba1579fd80682e51e933dfa8a (patch) | |
tree | be16e677a5009144cb52c602dcb7dfbc2f86b12a /fs | |
parent | bdaec334bbe7d234ca6ddd81aa74b2938d40e6b4 (diff) |
switch compat readv/writev variants to COMPAT_SYSCALL_DEFINE
... and take to fs/read_write.c
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/compat.c | 186 | ||||
-rw-r--r-- | fs/read_write.c | 197 | ||||
-rw-r--r-- | fs/read_write.h | 4 |
3 files changed, 195 insertions, 192 deletions
diff --git a/fs/compat.c b/fs/compat.c index daa3b771d64d..5058345dc279 100644 --- a/fs/compat.c +++ b/fs/compat.c | |||
@@ -1069,192 +1069,6 @@ asmlinkage long compat_sys_getdents64(unsigned int fd, | |||
1069 | } | 1069 | } |
1070 | #endif /* ! __ARCH_OMIT_COMPAT_SYS_GETDENTS64 */ | 1070 | #endif /* ! __ARCH_OMIT_COMPAT_SYS_GETDENTS64 */ |
1071 | 1071 | ||
1072 | static ssize_t compat_do_readv_writev(int type, struct file *file, | ||
1073 | const struct compat_iovec __user *uvector, | ||
1074 | unsigned long nr_segs, loff_t *pos) | ||
1075 | { | ||
1076 | compat_ssize_t tot_len; | ||
1077 | struct iovec iovstack[UIO_FASTIOV]; | ||
1078 | struct iovec *iov = iovstack; | ||
1079 | ssize_t ret; | ||
1080 | io_fn_t fn; | ||
1081 | iov_fn_t fnv; | ||
1082 | |||
1083 | ret = -EINVAL; | ||
1084 | if (!file->f_op) | ||
1085 | goto out; | ||
1086 | |||
1087 | ret = compat_rw_copy_check_uvector(type, uvector, nr_segs, | ||
1088 | UIO_FASTIOV, iovstack, &iov); | ||
1089 | if (ret <= 0) | ||
1090 | goto out; | ||
1091 | |||
1092 | tot_len = ret; | ||
1093 | ret = rw_verify_area(type, file, pos, tot_len); | ||
1094 | if (ret < 0) | ||
1095 | goto out; | ||
1096 | |||
1097 | fnv = NULL; | ||
1098 | if (type == READ) { | ||
1099 | fn = file->f_op->read; | ||
1100 | fnv = file->f_op->aio_read; | ||
1101 | } else { | ||
1102 | fn = (io_fn_t)file->f_op->write; | ||
1103 | fnv = file->f_op->aio_write; | ||
1104 | } | ||
1105 | |||
1106 | if (fnv) { | ||
1107 | file_start_write(file); | ||
1108 | ret = do_sync_readv_writev(file, iov, nr_segs, tot_len, | ||
1109 | pos, fnv); | ||
1110 | file_end_write(file); | ||
1111 | } else | ||
1112 | ret = do_loop_readv_writev(file, iov, nr_segs, pos, fn); | ||
1113 | |||
1114 | out: | ||
1115 | if (iov != iovstack) | ||
1116 | kfree(iov); | ||
1117 | if ((ret + (type == READ)) > 0) { | ||
1118 | if (type == READ) | ||
1119 | fsnotify_access(file); | ||
1120 | else | ||
1121 | fsnotify_modify(file); | ||
1122 | } | ||
1123 | return ret; | ||
1124 | } | ||
1125 | |||
1126 | static size_t compat_readv(struct file *file, | ||
1127 | const struct compat_iovec __user *vec, | ||
1128 | unsigned long vlen, loff_t *pos) | ||
1129 | { | ||
1130 | ssize_t ret = -EBADF; | ||
1131 | |||
1132 | if (!(file->f_mode & FMODE_READ)) | ||
1133 | goto out; | ||
1134 | |||
1135 | ret = -EINVAL; | ||
1136 | if (!file->f_op || (!file->f_op->aio_read && !file->f_op->read)) | ||
1137 | goto out; | ||
1138 | |||
1139 | ret = compat_do_readv_writev(READ, file, vec, vlen, pos); | ||
1140 | |||
1141 | out: | ||
1142 | if (ret > 0) | ||
1143 | add_rchar(current, ret); | ||
1144 | inc_syscr(current); | ||
1145 | return ret; | ||
1146 | } | ||
1147 | |||
1148 | asmlinkage ssize_t | ||
1149 | compat_sys_readv(unsigned long fd, const struct compat_iovec __user *vec, | ||
1150 | unsigned long vlen) | ||
1151 | { | ||
1152 | struct fd f = fdget(fd); | ||
1153 | ssize_t ret; | ||
1154 | loff_t pos; | ||
1155 | |||
1156 | if (!f.file) | ||
1157 | return -EBADF; | ||
1158 | pos = f.file->f_pos; | ||
1159 | ret = compat_readv(f.file, vec, vlen, &pos); | ||
1160 | f.file->f_pos = pos; | ||
1161 | fdput(f); | ||
1162 | return ret; | ||
1163 | } | ||
1164 | |||
1165 | asmlinkage ssize_t | ||
1166 | compat_sys_preadv64(unsigned long fd, const struct compat_iovec __user *vec, | ||
1167 | unsigned long vlen, loff_t pos) | ||
1168 | { | ||
1169 | struct fd f; | ||
1170 | ssize_t ret; | ||
1171 | |||
1172 | if (pos < 0) | ||
1173 | return -EINVAL; | ||
1174 | f = fdget(fd); | ||
1175 | if (!f.file) | ||
1176 | return -EBADF; | ||
1177 | ret = -ESPIPE; | ||
1178 | if (f.file->f_mode & FMODE_PREAD) | ||
1179 | ret = compat_readv(f.file, vec, vlen, &pos); | ||
1180 | fdput(f); | ||
1181 | return ret; | ||
1182 | } | ||
1183 | |||
1184 | asmlinkage ssize_t | ||
1185 | compat_sys_preadv(unsigned long fd, const struct compat_iovec __user *vec, | ||
1186 | unsigned long vlen, u32 pos_low, u32 pos_high) | ||
1187 | { | ||
1188 | loff_t pos = ((loff_t)pos_high << 32) | pos_low; | ||
1189 | return compat_sys_preadv64(fd, vec, vlen, pos); | ||
1190 | } | ||
1191 | |||
1192 | static size_t compat_writev(struct file *file, | ||
1193 | const struct compat_iovec __user *vec, | ||
1194 | unsigned long vlen, loff_t *pos) | ||
1195 | { | ||
1196 | ssize_t ret = -EBADF; | ||
1197 | |||
1198 | if (!(file->f_mode & FMODE_WRITE)) | ||
1199 | goto out; | ||
1200 | |||
1201 | ret = -EINVAL; | ||
1202 | if (!file->f_op || (!file->f_op->aio_write && !file->f_op->write)) | ||
1203 | goto out; | ||
1204 | |||
1205 | ret = compat_do_readv_writev(WRITE, file, vec, vlen, pos); | ||
1206 | |||
1207 | out: | ||
1208 | if (ret > 0) | ||
1209 | add_wchar(current, ret); | ||
1210 | inc_syscw(current); | ||
1211 | return ret; | ||
1212 | } | ||
1213 | |||
1214 | asmlinkage ssize_t | ||
1215 | compat_sys_writev(unsigned long fd, const struct compat_iovec __user *vec, | ||
1216 | unsigned long vlen) | ||
1217 | { | ||
1218 | struct fd f = fdget(fd); | ||
1219 | ssize_t ret; | ||
1220 | loff_t pos; | ||
1221 | |||
1222 | if (!f.file) | ||
1223 | return -EBADF; | ||
1224 | pos = f.file->f_pos; | ||
1225 | ret = compat_writev(f.file, vec, vlen, &pos); | ||
1226 | f.file->f_pos = pos; | ||
1227 | fdput(f); | ||
1228 | return ret; | ||
1229 | } | ||
1230 | |||
1231 | asmlinkage ssize_t | ||
1232 | compat_sys_pwritev64(unsigned long fd, const struct compat_iovec __user *vec, | ||
1233 | unsigned long vlen, loff_t pos) | ||
1234 | { | ||
1235 | struct fd f; | ||
1236 | ssize_t ret; | ||
1237 | |||
1238 | if (pos < 0) | ||
1239 | return -EINVAL; | ||
1240 | f = fdget(fd); | ||
1241 | if (!f.file) | ||
1242 | return -EBADF; | ||
1243 | ret = -ESPIPE; | ||
1244 | if (f.file->f_mode & FMODE_PWRITE) | ||
1245 | ret = compat_writev(f.file, vec, vlen, &pos); | ||
1246 | fdput(f); | ||
1247 | return ret; | ||
1248 | } | ||
1249 | |||
1250 | asmlinkage ssize_t | ||
1251 | compat_sys_pwritev(unsigned long fd, const struct compat_iovec __user *vec, | ||
1252 | unsigned long vlen, u32 pos_low, u32 pos_high) | ||
1253 | { | ||
1254 | loff_t pos = ((loff_t)pos_high << 32) | pos_low; | ||
1255 | return compat_sys_pwritev64(fd, vec, vlen, pos); | ||
1256 | } | ||
1257 | |||
1258 | asmlinkage long | 1072 | asmlinkage long |
1259 | compat_sys_vmsplice(int fd, const struct compat_iovec __user *iov32, | 1073 | compat_sys_vmsplice(int fd, const struct compat_iovec __user *iov32, |
1260 | unsigned int nr_segs, unsigned int flags) | 1074 | unsigned int nr_segs, unsigned int flags) |
diff --git a/fs/read_write.c b/fs/read_write.c index 3e1791a2cfd6..e6dd1c2d0592 100644 --- a/fs/read_write.c +++ b/fs/read_write.c | |||
@@ -591,7 +591,7 @@ unsigned long iov_shorten(struct iovec *iov, unsigned long nr_segs, size_t to) | |||
591 | } | 591 | } |
592 | EXPORT_SYMBOL(iov_shorten); | 592 | EXPORT_SYMBOL(iov_shorten); |
593 | 593 | ||
594 | ssize_t do_sync_readv_writev(struct file *filp, const struct iovec *iov, | 594 | static ssize_t do_sync_readv_writev(struct file *filp, const struct iovec *iov, |
595 | unsigned long nr_segs, size_t len, loff_t *ppos, iov_fn_t fn) | 595 | unsigned long nr_segs, size_t len, loff_t *ppos, iov_fn_t fn) |
596 | { | 596 | { |
597 | struct kiocb kiocb; | 597 | struct kiocb kiocb; |
@@ -616,7 +616,7 @@ ssize_t do_sync_readv_writev(struct file *filp, const struct iovec *iov, | |||
616 | } | 616 | } |
617 | 617 | ||
618 | /* Do it by hand, with file-ops */ | 618 | /* Do it by hand, with file-ops */ |
619 | ssize_t do_loop_readv_writev(struct file *filp, struct iovec *iov, | 619 | static ssize_t do_loop_readv_writev(struct file *filp, struct iovec *iov, |
620 | unsigned long nr_segs, loff_t *ppos, io_fn_t fn) | 620 | unsigned long nr_segs, loff_t *ppos, io_fn_t fn) |
621 | { | 621 | { |
622 | struct iovec *vector = iov; | 622 | struct iovec *vector = iov; |
@@ -898,6 +898,199 @@ SYSCALL_DEFINE5(pwritev, unsigned long, fd, const struct iovec __user *, vec, | |||
898 | return ret; | 898 | return ret; |
899 | } | 899 | } |
900 | 900 | ||
901 | #ifdef CONFIG_COMPAT | ||
902 | |||
903 | static ssize_t compat_do_readv_writev(int type, struct file *file, | ||
904 | const struct compat_iovec __user *uvector, | ||
905 | unsigned long nr_segs, loff_t *pos) | ||
906 | { | ||
907 | compat_ssize_t tot_len; | ||
908 | struct iovec iovstack[UIO_FASTIOV]; | ||
909 | struct iovec *iov = iovstack; | ||
910 | ssize_t ret; | ||
911 | io_fn_t fn; | ||
912 | iov_fn_t fnv; | ||
913 | |||
914 | ret = -EINVAL; | ||
915 | if (!file->f_op) | ||
916 | goto out; | ||
917 | |||
918 | ret = -EFAULT; | ||
919 | if (!access_ok(VERIFY_READ, uvector, nr_segs*sizeof(*uvector))) | ||
920 | goto out; | ||
921 | |||
922 | ret = compat_rw_copy_check_uvector(type, uvector, nr_segs, | ||
923 | UIO_FASTIOV, iovstack, &iov); | ||
924 | if (ret <= 0) | ||
925 | goto out; | ||
926 | |||
927 | tot_len = ret; | ||
928 | ret = rw_verify_area(type, file, pos, tot_len); | ||
929 | if (ret < 0) | ||
930 | goto out; | ||
931 | |||
932 | fnv = NULL; | ||
933 | if (type == READ) { | ||
934 | fn = file->f_op->read; | ||
935 | fnv = file->f_op->aio_read; | ||
936 | } else { | ||
937 | fn = (io_fn_t)file->f_op->write; | ||
938 | fnv = file->f_op->aio_write; | ||
939 | } | ||
940 | |||
941 | if (fnv) { | ||
942 | file_start_write(file); | ||
943 | ret = do_sync_readv_writev(file, iov, nr_segs, tot_len, | ||
944 | pos, fnv); | ||
945 | file_end_write(file); | ||
946 | } else | ||
947 | ret = do_loop_readv_writev(file, iov, nr_segs, pos, fn); | ||
948 | |||
949 | out: | ||
950 | if (iov != iovstack) | ||
951 | kfree(iov); | ||
952 | if ((ret + (type == READ)) > 0) { | ||
953 | if (type == READ) | ||
954 | fsnotify_access(file); | ||
955 | else | ||
956 | fsnotify_modify(file); | ||
957 | } | ||
958 | return ret; | ||
959 | } | ||
960 | |||
961 | static size_t compat_readv(struct file *file, | ||
962 | const struct compat_iovec __user *vec, | ||
963 | unsigned long vlen, loff_t *pos) | ||
964 | { | ||
965 | ssize_t ret = -EBADF; | ||
966 | |||
967 | if (!(file->f_mode & FMODE_READ)) | ||
968 | goto out; | ||
969 | |||
970 | ret = -EINVAL; | ||
971 | if (!file->f_op || (!file->f_op->aio_read && !file->f_op->read)) | ||
972 | goto out; | ||
973 | |||
974 | ret = compat_do_readv_writev(READ, file, vec, vlen, pos); | ||
975 | |||
976 | out: | ||
977 | if (ret > 0) | ||
978 | add_rchar(current, ret); | ||
979 | inc_syscr(current); | ||
980 | return ret; | ||
981 | } | ||
982 | |||
983 | COMPAT_SYSCALL_DEFINE3(readv, unsigned long, fd, | ||
984 | const struct compat_iovec __user *,vec, | ||
985 | unsigned long, vlen) | ||
986 | { | ||
987 | struct fd f = fdget(fd); | ||
988 | ssize_t ret; | ||
989 | loff_t pos; | ||
990 | |||
991 | if (!f.file) | ||
992 | return -EBADF; | ||
993 | pos = f.file->f_pos; | ||
994 | ret = compat_readv(f.file, vec, vlen, &pos); | ||
995 | f.file->f_pos = pos; | ||
996 | fdput(f); | ||
997 | return ret; | ||
998 | } | ||
999 | |||
1000 | COMPAT_SYSCALL_DEFINE4(preadv64, unsigned long, fd, | ||
1001 | const struct compat_iovec __user *,vec, | ||
1002 | unsigned long, vlen, loff_t, pos) | ||
1003 | { | ||
1004 | struct fd f; | ||
1005 | ssize_t ret; | ||
1006 | |||
1007 | if (pos < 0) | ||
1008 | return -EINVAL; | ||
1009 | f = fdget(fd); | ||
1010 | if (!f.file) | ||
1011 | return -EBADF; | ||
1012 | ret = -ESPIPE; | ||
1013 | if (f.file->f_mode & FMODE_PREAD) | ||
1014 | ret = compat_readv(f.file, vec, vlen, &pos); | ||
1015 | fdput(f); | ||
1016 | return ret; | ||
1017 | } | ||
1018 | |||
1019 | COMPAT_SYSCALL_DEFINE5(preadv, unsigned long, fd, | ||
1020 | const struct compat_iovec __user *,vec, | ||
1021 | unsigned long, vlen, u32, pos_low, u32, pos_high) | ||
1022 | { | ||
1023 | loff_t pos = ((loff_t)pos_high << 32) | pos_low; | ||
1024 | return compat_sys_preadv64(fd, vec, vlen, pos); | ||
1025 | } | ||
1026 | |||
1027 | static size_t compat_writev(struct file *file, | ||
1028 | const struct compat_iovec __user *vec, | ||
1029 | unsigned long vlen, loff_t *pos) | ||
1030 | { | ||
1031 | ssize_t ret = -EBADF; | ||
1032 | |||
1033 | if (!(file->f_mode & FMODE_WRITE)) | ||
1034 | goto out; | ||
1035 | |||
1036 | ret = -EINVAL; | ||
1037 | if (!file->f_op || (!file->f_op->aio_write && !file->f_op->write)) | ||
1038 | goto out; | ||
1039 | |||
1040 | ret = compat_do_readv_writev(WRITE, file, vec, vlen, pos); | ||
1041 | |||
1042 | out: | ||
1043 | if (ret > 0) | ||
1044 | add_wchar(current, ret); | ||
1045 | inc_syscw(current); | ||
1046 | return ret; | ||
1047 | } | ||
1048 | |||
1049 | COMPAT_SYSCALL_DEFINE3(writev, unsigned long, fd, | ||
1050 | const struct compat_iovec __user *, vec, | ||
1051 | unsigned long, vlen) | ||
1052 | { | ||
1053 | struct fd f = fdget(fd); | ||
1054 | ssize_t ret; | ||
1055 | loff_t pos; | ||
1056 | |||
1057 | if (!f.file) | ||
1058 | return -EBADF; | ||
1059 | pos = f.file->f_pos; | ||
1060 | ret = compat_writev(f.file, vec, vlen, &pos); | ||
1061 | f.file->f_pos = pos; | ||
1062 | fdput(f); | ||
1063 | return ret; | ||
1064 | } | ||
1065 | |||
1066 | COMPAT_SYSCALL_DEFINE4(pwritev64, unsigned long, fd, | ||
1067 | const struct compat_iovec __user *,vec, | ||
1068 | unsigned long, vlen, loff_t, pos) | ||
1069 | { | ||
1070 | struct fd f; | ||
1071 | ssize_t ret; | ||
1072 | |||
1073 | if (pos < 0) | ||
1074 | return -EINVAL; | ||
1075 | f = fdget(fd); | ||
1076 | if (!f.file) | ||
1077 | return -EBADF; | ||
1078 | ret = -ESPIPE; | ||
1079 | if (f.file->f_mode & FMODE_PWRITE) | ||
1080 | ret = compat_writev(f.file, vec, vlen, &pos); | ||
1081 | fdput(f); | ||
1082 | return ret; | ||
1083 | } | ||
1084 | |||
1085 | COMPAT_SYSCALL_DEFINE5(pwritev, unsigned long, fd, | ||
1086 | const struct compat_iovec __user *,vec, | ||
1087 | unsigned long, vlen, u32, pos_low, u32, pos_high) | ||
1088 | { | ||
1089 | loff_t pos = ((loff_t)pos_high << 32) | pos_low; | ||
1090 | return compat_sys_pwritev64(fd, vec, vlen, pos); | ||
1091 | } | ||
1092 | #endif | ||
1093 | |||
901 | ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, size_t count, | 1094 | ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, size_t count, |
902 | loff_t max) | 1095 | loff_t max) |
903 | { | 1096 | { |
diff --git a/fs/read_write.h b/fs/read_write.h index d3e00ef67420..b98780664ffa 100644 --- a/fs/read_write.h +++ b/fs/read_write.h | |||
@@ -8,9 +8,5 @@ typedef ssize_t (*io_fn_t)(struct file *, char __user *, size_t, loff_t *); | |||
8 | typedef ssize_t (*iov_fn_t)(struct kiocb *, const struct iovec *, | 8 | typedef ssize_t (*iov_fn_t)(struct kiocb *, const struct iovec *, |
9 | unsigned long, loff_t); | 9 | unsigned long, loff_t); |
10 | 10 | ||
11 | ssize_t do_sync_readv_writev(struct file *filp, const struct iovec *iov, | ||
12 | unsigned long nr_segs, size_t len, loff_t *ppos, iov_fn_t fn); | ||
13 | ssize_t do_loop_readv_writev(struct file *filp, struct iovec *iov, | ||
14 | unsigned long nr_segs, loff_t *ppos, io_fn_t fn); | ||
15 | ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, size_t count, | 11 | ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, size_t count, |
16 | loff_t max); | 12 | loff_t max); |