diff options
-rw-r--r-- | fs/aio.c | 69 | ||||
-rw-r--r-- | include/linux/aio.h | 11 |
2 files changed, 42 insertions, 38 deletions
@@ -723,8 +723,6 @@ static void kiocb_free(struct kiocb *req) | |||
723 | eventfd_ctx_put(req->ki_eventfd); | 723 | eventfd_ctx_put(req->ki_eventfd); |
724 | if (req->ki_dtor) | 724 | if (req->ki_dtor) |
725 | req->ki_dtor(req); | 725 | req->ki_dtor(req); |
726 | if (req->ki_iovec != &req->ki_inline_vec) | ||
727 | kfree(req->ki_iovec); | ||
728 | kmem_cache_free(kiocb_cachep, req); | 726 | kmem_cache_free(kiocb_cachep, req); |
729 | } | 727 | } |
730 | 728 | ||
@@ -1054,24 +1052,26 @@ SYSCALL_DEFINE1(io_destroy, aio_context_t, ctx) | |||
1054 | typedef ssize_t (aio_rw_op)(struct kiocb *, const struct iovec *, | 1052 | typedef ssize_t (aio_rw_op)(struct kiocb *, const struct iovec *, |
1055 | unsigned long, loff_t); | 1053 | unsigned long, loff_t); |
1056 | 1054 | ||
1057 | static ssize_t aio_setup_vectored_rw(int rw, struct kiocb *kiocb, bool compat) | 1055 | static ssize_t aio_setup_vectored_rw(struct kiocb *kiocb, |
1056 | int rw, char __user *buf, | ||
1057 | unsigned long *nr_segs, | ||
1058 | struct iovec **iovec, | ||
1059 | bool compat) | ||
1058 | { | 1060 | { |
1059 | ssize_t ret; | 1061 | ssize_t ret; |
1060 | 1062 | ||
1061 | kiocb->ki_nr_segs = kiocb->ki_nbytes; | 1063 | *nr_segs = kiocb->ki_nbytes; |
1062 | 1064 | ||
1063 | #ifdef CONFIG_COMPAT | 1065 | #ifdef CONFIG_COMPAT |
1064 | if (compat) | 1066 | if (compat) |
1065 | ret = compat_rw_copy_check_uvector(rw, | 1067 | ret = compat_rw_copy_check_uvector(rw, |
1066 | (struct compat_iovec __user *)kiocb->ki_buf, | 1068 | (struct compat_iovec __user *)buf, |
1067 | kiocb->ki_nr_segs, 1, &kiocb->ki_inline_vec, | 1069 | *nr_segs, 1, *iovec, iovec); |
1068 | &kiocb->ki_iovec); | ||
1069 | else | 1070 | else |
1070 | #endif | 1071 | #endif |
1071 | ret = rw_copy_check_uvector(rw, | 1072 | ret = rw_copy_check_uvector(rw, |
1072 | (struct iovec __user *)kiocb->ki_buf, | 1073 | (struct iovec __user *)buf, |
1073 | kiocb->ki_nr_segs, 1, &kiocb->ki_inline_vec, | 1074 | *nr_segs, 1, *iovec, iovec); |
1074 | &kiocb->ki_iovec); | ||
1075 | if (ret < 0) | 1075 | if (ret < 0) |
1076 | return ret; | 1076 | return ret; |
1077 | 1077 | ||
@@ -1080,15 +1080,17 @@ static ssize_t aio_setup_vectored_rw(int rw, struct kiocb *kiocb, bool compat) | |||
1080 | return 0; | 1080 | return 0; |
1081 | } | 1081 | } |
1082 | 1082 | ||
1083 | static ssize_t aio_setup_single_vector(int rw, struct kiocb *kiocb) | 1083 | static ssize_t aio_setup_single_vector(struct kiocb *kiocb, |
1084 | int rw, char __user *buf, | ||
1085 | unsigned long *nr_segs, | ||
1086 | struct iovec *iovec) | ||
1084 | { | 1087 | { |
1085 | if (unlikely(!access_ok(!rw, kiocb->ki_buf, kiocb->ki_nbytes))) | 1088 | if (unlikely(!access_ok(!rw, buf, kiocb->ki_nbytes))) |
1086 | return -EFAULT; | 1089 | return -EFAULT; |
1087 | 1090 | ||
1088 | kiocb->ki_iovec = &kiocb->ki_inline_vec; | 1091 | iovec->iov_base = buf; |
1089 | kiocb->ki_iovec->iov_base = kiocb->ki_buf; | 1092 | iovec->iov_len = kiocb->ki_nbytes; |
1090 | kiocb->ki_iovec->iov_len = kiocb->ki_nbytes; | 1093 | *nr_segs = 1; |
1091 | kiocb->ki_nr_segs = 1; | ||
1092 | return 0; | 1094 | return 0; |
1093 | } | 1095 | } |
1094 | 1096 | ||
@@ -1097,15 +1099,18 @@ static ssize_t aio_setup_single_vector(int rw, struct kiocb *kiocb) | |||
1097 | * Performs the initial checks and aio retry method | 1099 | * Performs the initial checks and aio retry method |
1098 | * setup for the kiocb at the time of io submission. | 1100 | * setup for the kiocb at the time of io submission. |
1099 | */ | 1101 | */ |
1100 | static ssize_t aio_run_iocb(struct kiocb *req, bool compat) | 1102 | static ssize_t aio_run_iocb(struct kiocb *req, unsigned opcode, |
1103 | char __user *buf, bool compat) | ||
1101 | { | 1104 | { |
1102 | struct file *file = req->ki_filp; | 1105 | struct file *file = req->ki_filp; |
1103 | ssize_t ret; | 1106 | ssize_t ret; |
1107 | unsigned long nr_segs; | ||
1104 | int rw; | 1108 | int rw; |
1105 | fmode_t mode; | 1109 | fmode_t mode; |
1106 | aio_rw_op *rw_op; | 1110 | aio_rw_op *rw_op; |
1111 | struct iovec inline_vec, *iovec = &inline_vec; | ||
1107 | 1112 | ||
1108 | switch (req->ki_opcode) { | 1113 | switch (opcode) { |
1109 | case IOCB_CMD_PREAD: | 1114 | case IOCB_CMD_PREAD: |
1110 | case IOCB_CMD_PREADV: | 1115 | case IOCB_CMD_PREADV: |
1111 | mode = FMODE_READ; | 1116 | mode = FMODE_READ; |
@@ -1126,16 +1131,21 @@ rw_common: | |||
1126 | if (!rw_op) | 1131 | if (!rw_op) |
1127 | return -EINVAL; | 1132 | return -EINVAL; |
1128 | 1133 | ||
1129 | ret = (req->ki_opcode == IOCB_CMD_PREADV || | 1134 | ret = (opcode == IOCB_CMD_PREADV || |
1130 | req->ki_opcode == IOCB_CMD_PWRITEV) | 1135 | opcode == IOCB_CMD_PWRITEV) |
1131 | ? aio_setup_vectored_rw(rw, req, compat) | 1136 | ? aio_setup_vectored_rw(req, rw, buf, &nr_segs, |
1132 | : aio_setup_single_vector(rw, req); | 1137 | &iovec, compat) |
1138 | : aio_setup_single_vector(req, rw, buf, &nr_segs, | ||
1139 | iovec); | ||
1133 | if (ret) | 1140 | if (ret) |
1134 | return ret; | 1141 | return ret; |
1135 | 1142 | ||
1136 | ret = rw_verify_area(rw, file, &req->ki_pos, req->ki_nbytes); | 1143 | ret = rw_verify_area(rw, file, &req->ki_pos, req->ki_nbytes); |
1137 | if (ret < 0) | 1144 | if (ret < 0) { |
1145 | if (iovec != &inline_vec) | ||
1146 | kfree(iovec); | ||
1138 | return ret; | 1147 | return ret; |
1148 | } | ||
1139 | 1149 | ||
1140 | req->ki_nbytes = ret; | 1150 | req->ki_nbytes = ret; |
1141 | 1151 | ||
@@ -1149,8 +1159,7 @@ rw_common: | |||
1149 | if (rw == WRITE) | 1159 | if (rw == WRITE) |
1150 | file_start_write(file); | 1160 | file_start_write(file); |
1151 | 1161 | ||
1152 | ret = rw_op(req, req->ki_iovec, | 1162 | ret = rw_op(req, iovec, nr_segs, req->ki_pos); |
1153 | req->ki_nr_segs, req->ki_pos); | ||
1154 | 1163 | ||
1155 | if (rw == WRITE) | 1164 | if (rw == WRITE) |
1156 | file_end_write(file); | 1165 | file_end_write(file); |
@@ -1175,6 +1184,9 @@ rw_common: | |||
1175 | return -EINVAL; | 1184 | return -EINVAL; |
1176 | } | 1185 | } |
1177 | 1186 | ||
1187 | if (iovec != &inline_vec) | ||
1188 | kfree(iovec); | ||
1189 | |||
1178 | if (ret != -EIOCBQUEUED) { | 1190 | if (ret != -EIOCBQUEUED) { |
1179 | /* | 1191 | /* |
1180 | * There's no easy way to restart the syscall since other AIO's | 1192 | * There's no easy way to restart the syscall since other AIO's |
@@ -1246,12 +1258,11 @@ static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, | |||
1246 | req->ki_obj.user = user_iocb; | 1258 | req->ki_obj.user = user_iocb; |
1247 | req->ki_user_data = iocb->aio_data; | 1259 | req->ki_user_data = iocb->aio_data; |
1248 | req->ki_pos = iocb->aio_offset; | 1260 | req->ki_pos = iocb->aio_offset; |
1249 | |||
1250 | req->ki_buf = (char __user *)(unsigned long)iocb->aio_buf; | ||
1251 | req->ki_nbytes = iocb->aio_nbytes; | 1261 | req->ki_nbytes = iocb->aio_nbytes; |
1252 | req->ki_opcode = iocb->aio_lio_opcode; | ||
1253 | 1262 | ||
1254 | ret = aio_run_iocb(req, compat); | 1263 | ret = aio_run_iocb(req, iocb->aio_lio_opcode, |
1264 | (char __user *)(unsigned long)iocb->aio_buf, | ||
1265 | compat); | ||
1255 | if (ret) | 1266 | if (ret) |
1256 | goto out_put_req; | 1267 | goto out_put_req; |
1257 | 1268 | ||
diff --git a/include/linux/aio.h b/include/linux/aio.h index 7bb766e73968..b570472355d1 100644 --- a/include/linux/aio.h +++ b/include/linux/aio.h | |||
@@ -36,6 +36,7 @@ struct kiocb { | |||
36 | struct kioctx *ki_ctx; /* NULL for sync ops */ | 36 | struct kioctx *ki_ctx; /* NULL for sync ops */ |
37 | kiocb_cancel_fn *ki_cancel; | 37 | kiocb_cancel_fn *ki_cancel; |
38 | void (*ki_dtor)(struct kiocb *); | 38 | void (*ki_dtor)(struct kiocb *); |
39 | void *private; | ||
39 | 40 | ||
40 | union { | 41 | union { |
41 | void __user *user; | 42 | void __user *user; |
@@ -44,15 +45,7 @@ struct kiocb { | |||
44 | 45 | ||
45 | __u64 ki_user_data; /* user's data for completion */ | 46 | __u64 ki_user_data; /* user's data for completion */ |
46 | loff_t ki_pos; | 47 | loff_t ki_pos; |
47 | 48 | size_t ki_nbytes; /* copy of iocb->aio_nbytes */ | |
48 | void *private; | ||
49 | /* State that we remember to be able to restart/retry */ | ||
50 | unsigned short ki_opcode; | ||
51 | size_t ki_nbytes; /* copy of iocb->aio_nbytes */ | ||
52 | char __user *ki_buf; /* remaining iocb->aio_buf */ | ||
53 | struct iovec ki_inline_vec; /* inline vector */ | ||
54 | struct iovec *ki_iovec; | ||
55 | unsigned long ki_nr_segs; | ||
56 | 49 | ||
57 | struct list_head ki_list; /* the aio core uses this | 50 | struct list_head ki_list; /* the aio core uses this |
58 | * for cancellation */ | 51 | * for cancellation */ |