aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/aio.c69
-rw-r--r--include/linux/aio.h11
2 files changed, 42 insertions, 38 deletions
diff --git a/fs/aio.c b/fs/aio.c
index d00904db69b7..09fe1f334631 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -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)
1054typedef ssize_t (aio_rw_op)(struct kiocb *, const struct iovec *, 1052typedef ssize_t (aio_rw_op)(struct kiocb *, const struct iovec *,
1055 unsigned long, loff_t); 1053 unsigned long, loff_t);
1056 1054
1057static ssize_t aio_setup_vectored_rw(int rw, struct kiocb *kiocb, bool compat) 1055static 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
1083static ssize_t aio_setup_single_vector(int rw, struct kiocb *kiocb) 1083static 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 */
1100static ssize_t aio_run_iocb(struct kiocb *req, bool compat) 1102static 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 */