aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2013-03-20 10:42:10 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2013-04-09 14:12:56 -0400
commit72ec35163f9f728ba1579fd80682e51e933dfa8a (patch)
treebe16e677a5009144cb52c602dcb7dfbc2f86b12a /fs
parentbdaec334bbe7d234ca6ddd81aa74b2938d40e6b4 (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.c186
-rw-r--r--fs/read_write.c197
-rw-r--r--fs/read_write.h4
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
1072static 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
1114out:
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
1126static 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
1141out:
1142 if (ret > 0)
1143 add_rchar(current, ret);
1144 inc_syscr(current);
1145 return ret;
1146}
1147
1148asmlinkage ssize_t
1149compat_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
1165asmlinkage ssize_t
1166compat_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
1184asmlinkage ssize_t
1185compat_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
1192static 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
1207out:
1208 if (ret > 0)
1209 add_wchar(current, ret);
1210 inc_syscw(current);
1211 return ret;
1212}
1213
1214asmlinkage ssize_t
1215compat_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
1231asmlinkage ssize_t
1232compat_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
1250asmlinkage ssize_t
1251compat_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
1258asmlinkage long 1072asmlinkage long
1259compat_sys_vmsplice(int fd, const struct compat_iovec __user *iov32, 1073compat_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}
592EXPORT_SYMBOL(iov_shorten); 592EXPORT_SYMBOL(iov_shorten);
593 593
594ssize_t do_sync_readv_writev(struct file *filp, const struct iovec *iov, 594static 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 */
619ssize_t do_loop_readv_writev(struct file *filp, struct iovec *iov, 619static 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
903static 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
949out:
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
961static 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
976out:
977 if (ret > 0)
978 add_rchar(current, ret);
979 inc_syscr(current);
980 return ret;
981}
982
983COMPAT_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
1000COMPAT_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
1019COMPAT_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
1027static 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
1042out:
1043 if (ret > 0)
1044 add_wchar(current, ret);
1045 inc_syscw(current);
1046 return ret;
1047}
1048
1049COMPAT_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
1066COMPAT_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
1085COMPAT_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
901ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, size_t count, 1094ssize_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 *);
8typedef ssize_t (*iov_fn_t)(struct kiocb *, const struct iovec *, 8typedef ssize_t (*iov_fn_t)(struct kiocb *, const struct iovec *,
9 unsigned long, loff_t); 9 unsigned long, loff_t);
10 10
11ssize_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);
13ssize_t do_loop_readv_writev(struct file *filp, struct iovec *iov,
14 unsigned long nr_segs, loff_t *ppos, io_fn_t fn);
15ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, size_t count, 11ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, size_t count,
16 loff_t max); 12 loff_t max);