diff options
author | Kent Overstreet <koverstreet@google.com> | 2013-05-07 19:19:11 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-07 22:46:02 -0400 |
commit | 41ef4eb8eef8d06bc1399e7b00c940d771554711 (patch) | |
tree | 3b8194de916d638f73394ed4b9c8910bbab04feb /fs/aio.c | |
parent | 8a6608907cf165b3ae658c9de2efe6af4be68bff (diff) |
aio: kill ki_retry
Thanks to Zach Brown's work to rip out the retry infrastructure, we don't
need this anymore - ki_retry was only called right after the kiocb was
initialized.
This also refactors and trims some duplicated code, as well as cleaning up
the refcounting/error handling a bit.
[akpm@linux-foundation.org: use fmode_t in aio_run_iocb()]
[akpm@linux-foundation.org: fix file_start_write/file_end_write tests]
[akpm@linux-foundation.org: coding-style fixes]
Signed-off-by: Kent Overstreet <koverstreet@google.com>
Cc: Zach Brown <zab@redhat.com>
Cc: Felipe Balbi <balbi@ti.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Mark Fasheh <mfasheh@suse.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Asai Thambi S P <asamymuthupa@micron.com>
Cc: Selvan Mani <smani@micron.com>
Cc: Sam Bradshaw <sbradshaw@micron.com>
Cc: Jeff Moyer <jmoyer@redhat.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Benjamin LaHaise <bcrl@kvack.org>
Reviewed-by: "Theodore Ts'o" <tytso@mit.edu>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/aio.c')
-rw-r--r-- | fs/aio.c | 224 |
1 files changed, 85 insertions, 139 deletions
@@ -903,30 +903,21 @@ static void aio_advance_iovec(struct kiocb *iocb, ssize_t ret) | |||
903 | BUG_ON(ret > 0 && iocb->ki_left == 0); | 903 | BUG_ON(ret > 0 && iocb->ki_left == 0); |
904 | } | 904 | } |
905 | 905 | ||
906 | static ssize_t aio_rw_vect_retry(struct kiocb *iocb) | 906 | typedef ssize_t (aio_rw_op)(struct kiocb *, const struct iovec *, |
907 | unsigned long, loff_t); | ||
908 | |||
909 | static ssize_t aio_rw_vect_retry(struct kiocb *iocb, int rw, aio_rw_op *rw_op) | ||
907 | { | 910 | { |
908 | struct file *file = iocb->ki_filp; | 911 | struct file *file = iocb->ki_filp; |
909 | struct address_space *mapping = file->f_mapping; | 912 | struct address_space *mapping = file->f_mapping; |
910 | struct inode *inode = mapping->host; | 913 | struct inode *inode = mapping->host; |
911 | ssize_t (*rw_op)(struct kiocb *, const struct iovec *, | ||
912 | unsigned long, loff_t); | ||
913 | ssize_t ret = 0; | 914 | ssize_t ret = 0; |
914 | unsigned short opcode; | ||
915 | |||
916 | if ((iocb->ki_opcode == IOCB_CMD_PREADV) || | ||
917 | (iocb->ki_opcode == IOCB_CMD_PREAD)) { | ||
918 | rw_op = file->f_op->aio_read; | ||
919 | opcode = IOCB_CMD_PREADV; | ||
920 | } else { | ||
921 | rw_op = file->f_op->aio_write; | ||
922 | opcode = IOCB_CMD_PWRITEV; | ||
923 | } | ||
924 | 915 | ||
925 | /* This matches the pread()/pwrite() logic */ | 916 | /* This matches the pread()/pwrite() logic */ |
926 | if (iocb->ki_pos < 0) | 917 | if (iocb->ki_pos < 0) |
927 | return -EINVAL; | 918 | return -EINVAL; |
928 | 919 | ||
929 | if (opcode == IOCB_CMD_PWRITEV) | 920 | if (rw == WRITE) |
930 | file_start_write(file); | 921 | file_start_write(file); |
931 | do { | 922 | do { |
932 | ret = rw_op(iocb, &iocb->ki_iovec[iocb->ki_cur_seg], | 923 | ret = rw_op(iocb, &iocb->ki_iovec[iocb->ki_cur_seg], |
@@ -938,9 +929,9 @@ static ssize_t aio_rw_vect_retry(struct kiocb *iocb) | |||
938 | /* retry all partial writes. retry partial reads as long as its a | 929 | /* retry all partial writes. retry partial reads as long as its a |
939 | * regular file. */ | 930 | * regular file. */ |
940 | } while (ret > 0 && iocb->ki_left > 0 && | 931 | } while (ret > 0 && iocb->ki_left > 0 && |
941 | (opcode == IOCB_CMD_PWRITEV || | 932 | (rw == WRITE || |
942 | (!S_ISFIFO(inode->i_mode) && !S_ISSOCK(inode->i_mode)))); | 933 | (!S_ISFIFO(inode->i_mode) && !S_ISSOCK(inode->i_mode)))); |
943 | if (opcode == IOCB_CMD_PWRITEV) | 934 | if (rw == WRITE) |
944 | file_end_write(file); | 935 | file_end_write(file); |
945 | 936 | ||
946 | /* This means we must have transferred all that we could */ | 937 | /* This means we must have transferred all that we could */ |
@@ -950,7 +941,7 @@ static ssize_t aio_rw_vect_retry(struct kiocb *iocb) | |||
950 | 941 | ||
951 | /* If we managed to write some out we return that, rather than | 942 | /* If we managed to write some out we return that, rather than |
952 | * the eventual error. */ | 943 | * the eventual error. */ |
953 | if (opcode == IOCB_CMD_PWRITEV | 944 | if (rw == WRITE |
954 | && ret < 0 && ret != -EIOCBQUEUED | 945 | && ret < 0 && ret != -EIOCBQUEUED |
955 | && iocb->ki_nbytes - iocb->ki_left) | 946 | && iocb->ki_nbytes - iocb->ki_left) |
956 | ret = iocb->ki_nbytes - iocb->ki_left; | 947 | ret = iocb->ki_nbytes - iocb->ki_left; |
@@ -958,73 +949,41 @@ static ssize_t aio_rw_vect_retry(struct kiocb *iocb) | |||
958 | return ret; | 949 | return ret; |
959 | } | 950 | } |
960 | 951 | ||
961 | static ssize_t aio_fdsync(struct kiocb *iocb) | 952 | static ssize_t aio_setup_vectored_rw(int rw, struct kiocb *kiocb, bool compat) |
962 | { | ||
963 | struct file *file = iocb->ki_filp; | ||
964 | ssize_t ret = -EINVAL; | ||
965 | |||
966 | if (file->f_op->aio_fsync) | ||
967 | ret = file->f_op->aio_fsync(iocb, 1); | ||
968 | return ret; | ||
969 | } | ||
970 | |||
971 | static ssize_t aio_fsync(struct kiocb *iocb) | ||
972 | { | ||
973 | struct file *file = iocb->ki_filp; | ||
974 | ssize_t ret = -EINVAL; | ||
975 | |||
976 | if (file->f_op->aio_fsync) | ||
977 | ret = file->f_op->aio_fsync(iocb, 0); | ||
978 | return ret; | ||
979 | } | ||
980 | |||
981 | static ssize_t aio_setup_vectored_rw(int type, struct kiocb *kiocb, bool compat) | ||
982 | { | 953 | { |
983 | ssize_t ret; | 954 | ssize_t ret; |
984 | 955 | ||
956 | kiocb->ki_nr_segs = kiocb->ki_nbytes; | ||
957 | |||
985 | #ifdef CONFIG_COMPAT | 958 | #ifdef CONFIG_COMPAT |
986 | if (compat) | 959 | if (compat) |
987 | ret = compat_rw_copy_check_uvector(type, | 960 | ret = compat_rw_copy_check_uvector(rw, |
988 | (struct compat_iovec __user *)kiocb->ki_buf, | 961 | (struct compat_iovec __user *)kiocb->ki_buf, |
989 | kiocb->ki_nbytes, 1, &kiocb->ki_inline_vec, | 962 | kiocb->ki_nr_segs, 1, &kiocb->ki_inline_vec, |
990 | &kiocb->ki_iovec); | 963 | &kiocb->ki_iovec); |
991 | else | 964 | else |
992 | #endif | 965 | #endif |
993 | ret = rw_copy_check_uvector(type, | 966 | ret = rw_copy_check_uvector(rw, |
994 | (struct iovec __user *)kiocb->ki_buf, | 967 | (struct iovec __user *)kiocb->ki_buf, |
995 | kiocb->ki_nbytes, 1, &kiocb->ki_inline_vec, | 968 | kiocb->ki_nr_segs, 1, &kiocb->ki_inline_vec, |
996 | &kiocb->ki_iovec); | 969 | &kiocb->ki_iovec); |
997 | if (ret < 0) | 970 | if (ret < 0) |
998 | goto out; | 971 | return ret; |
999 | |||
1000 | ret = rw_verify_area(type, kiocb->ki_filp, &kiocb->ki_pos, ret); | ||
1001 | if (ret < 0) | ||
1002 | goto out; | ||
1003 | 972 | ||
1004 | kiocb->ki_nr_segs = kiocb->ki_nbytes; | 973 | /* ki_nbytes now reflect bytes instead of segs */ |
1005 | kiocb->ki_cur_seg = 0; | ||
1006 | /* ki_nbytes/left now reflect bytes instead of segs */ | ||
1007 | kiocb->ki_nbytes = ret; | 974 | kiocb->ki_nbytes = ret; |
1008 | kiocb->ki_left = ret; | 975 | return 0; |
1009 | |||
1010 | ret = 0; | ||
1011 | out: | ||
1012 | return ret; | ||
1013 | } | 976 | } |
1014 | 977 | ||
1015 | static ssize_t aio_setup_single_vector(int type, struct file * file, struct kiocb *kiocb) | 978 | static ssize_t aio_setup_single_vector(int rw, struct kiocb *kiocb) |
1016 | { | 979 | { |
1017 | int bytes; | 980 | if (unlikely(!access_ok(!rw, kiocb->ki_buf, kiocb->ki_nbytes))) |
1018 | 981 | return -EFAULT; | |
1019 | bytes = rw_verify_area(type, file, &kiocb->ki_pos, kiocb->ki_left); | ||
1020 | if (bytes < 0) | ||
1021 | return bytes; | ||
1022 | 982 | ||
1023 | kiocb->ki_iovec = &kiocb->ki_inline_vec; | 983 | kiocb->ki_iovec = &kiocb->ki_inline_vec; |
1024 | kiocb->ki_iovec->iov_base = kiocb->ki_buf; | 984 | kiocb->ki_iovec->iov_base = kiocb->ki_buf; |
1025 | kiocb->ki_iovec->iov_len = bytes; | 985 | kiocb->ki_iovec->iov_len = kiocb->ki_nbytes; |
1026 | kiocb->ki_nr_segs = 1; | 986 | kiocb->ki_nr_segs = 1; |
1027 | kiocb->ki_cur_seg = 0; | ||
1028 | return 0; | 987 | return 0; |
1029 | } | 988 | } |
1030 | 989 | ||
@@ -1033,81 +992,82 @@ static ssize_t aio_setup_single_vector(int type, struct file * file, struct kioc | |||
1033 | * Performs the initial checks and aio retry method | 992 | * Performs the initial checks and aio retry method |
1034 | * setup for the kiocb at the time of io submission. | 993 | * setup for the kiocb at the time of io submission. |
1035 | */ | 994 | */ |
1036 | static ssize_t aio_setup_iocb(struct kiocb *kiocb, bool compat) | 995 | static ssize_t aio_run_iocb(struct kiocb *req, bool compat) |
1037 | { | 996 | { |
1038 | struct file *file = kiocb->ki_filp; | 997 | struct file *file = req->ki_filp; |
1039 | ssize_t ret = 0; | 998 | ssize_t ret; |
999 | int rw; | ||
1000 | fmode_t mode; | ||
1001 | aio_rw_op *rw_op; | ||
1040 | 1002 | ||
1041 | switch (kiocb->ki_opcode) { | 1003 | switch (req->ki_opcode) { |
1042 | case IOCB_CMD_PREAD: | 1004 | case IOCB_CMD_PREAD: |
1043 | ret = -EBADF; | ||
1044 | if (unlikely(!(file->f_mode & FMODE_READ))) | ||
1045 | break; | ||
1046 | ret = -EFAULT; | ||
1047 | if (unlikely(!access_ok(VERIFY_WRITE, kiocb->ki_buf, | ||
1048 | kiocb->ki_left))) | ||
1049 | break; | ||
1050 | ret = aio_setup_single_vector(READ, file, kiocb); | ||
1051 | if (ret) | ||
1052 | break; | ||
1053 | ret = -EINVAL; | ||
1054 | if (file->f_op->aio_read) | ||
1055 | kiocb->ki_retry = aio_rw_vect_retry; | ||
1056 | break; | ||
1057 | case IOCB_CMD_PWRITE: | ||
1058 | ret = -EBADF; | ||
1059 | if (unlikely(!(file->f_mode & FMODE_WRITE))) | ||
1060 | break; | ||
1061 | ret = -EFAULT; | ||
1062 | if (unlikely(!access_ok(VERIFY_READ, kiocb->ki_buf, | ||
1063 | kiocb->ki_left))) | ||
1064 | break; | ||
1065 | ret = aio_setup_single_vector(WRITE, file, kiocb); | ||
1066 | if (ret) | ||
1067 | break; | ||
1068 | ret = -EINVAL; | ||
1069 | if (file->f_op->aio_write) | ||
1070 | kiocb->ki_retry = aio_rw_vect_retry; | ||
1071 | break; | ||
1072 | case IOCB_CMD_PREADV: | 1005 | case IOCB_CMD_PREADV: |
1073 | ret = -EBADF; | 1006 | mode = FMODE_READ; |
1074 | if (unlikely(!(file->f_mode & FMODE_READ))) | 1007 | rw = READ; |
1075 | break; | 1008 | rw_op = file->f_op->aio_read; |
1076 | ret = aio_setup_vectored_rw(READ, kiocb, compat); | 1009 | goto rw_common; |
1077 | if (ret) | 1010 | |
1078 | break; | 1011 | case IOCB_CMD_PWRITE: |
1079 | ret = -EINVAL; | ||
1080 | if (file->f_op->aio_read) | ||
1081 | kiocb->ki_retry = aio_rw_vect_retry; | ||
1082 | break; | ||
1083 | case IOCB_CMD_PWRITEV: | 1012 | case IOCB_CMD_PWRITEV: |
1084 | ret = -EBADF; | 1013 | mode = FMODE_WRITE; |
1085 | if (unlikely(!(file->f_mode & FMODE_WRITE))) | 1014 | rw = WRITE; |
1086 | break; | 1015 | rw_op = file->f_op->aio_write; |
1087 | ret = aio_setup_vectored_rw(WRITE, kiocb, compat); | 1016 | goto rw_common; |
1017 | rw_common: | ||
1018 | if (unlikely(!(file->f_mode & mode))) | ||
1019 | return -EBADF; | ||
1020 | |||
1021 | if (!rw_op) | ||
1022 | return -EINVAL; | ||
1023 | |||
1024 | ret = (req->ki_opcode == IOCB_CMD_PREADV || | ||
1025 | req->ki_opcode == IOCB_CMD_PWRITEV) | ||
1026 | ? aio_setup_vectored_rw(rw, req, compat) | ||
1027 | : aio_setup_single_vector(rw, req); | ||
1088 | if (ret) | 1028 | if (ret) |
1089 | break; | 1029 | return ret; |
1090 | ret = -EINVAL; | 1030 | |
1091 | if (file->f_op->aio_write) | 1031 | ret = rw_verify_area(rw, file, &req->ki_pos, req->ki_nbytes); |
1092 | kiocb->ki_retry = aio_rw_vect_retry; | 1032 | if (ret < 0) |
1033 | return ret; | ||
1034 | |||
1035 | req->ki_nbytes = ret; | ||
1036 | req->ki_left = ret; | ||
1037 | |||
1038 | ret = aio_rw_vect_retry(req, rw, rw_op); | ||
1093 | break; | 1039 | break; |
1040 | |||
1094 | case IOCB_CMD_FDSYNC: | 1041 | case IOCB_CMD_FDSYNC: |
1095 | ret = -EINVAL; | 1042 | if (!file->f_op->aio_fsync) |
1096 | if (file->f_op->aio_fsync) | 1043 | return -EINVAL; |
1097 | kiocb->ki_retry = aio_fdsync; | 1044 | |
1045 | ret = file->f_op->aio_fsync(req, 1); | ||
1098 | break; | 1046 | break; |
1047 | |||
1099 | case IOCB_CMD_FSYNC: | 1048 | case IOCB_CMD_FSYNC: |
1100 | ret = -EINVAL; | 1049 | if (!file->f_op->aio_fsync) |
1101 | if (file->f_op->aio_fsync) | 1050 | return -EINVAL; |
1102 | kiocb->ki_retry = aio_fsync; | 1051 | |
1052 | ret = file->f_op->aio_fsync(req, 0); | ||
1103 | break; | 1053 | break; |
1054 | |||
1104 | default: | 1055 | default: |
1105 | pr_debug("EINVAL: no operation provided\n"); | 1056 | pr_debug("EINVAL: no operation provided\n"); |
1106 | ret = -EINVAL; | 1057 | return -EINVAL; |
1107 | } | 1058 | } |
1108 | 1059 | ||
1109 | if (!kiocb->ki_retry) | 1060 | if (ret != -EIOCBQUEUED) { |
1110 | return ret; | 1061 | /* |
1062 | * There's no easy way to restart the syscall since other AIO's | ||
1063 | * may be already running. Just fail this IO with EINTR. | ||
1064 | */ | ||
1065 | if (unlikely(ret == -ERESTARTSYS || ret == -ERESTARTNOINTR || | ||
1066 | ret == -ERESTARTNOHAND || | ||
1067 | ret == -ERESTART_RESTARTBLOCK)) | ||
1068 | ret = -EINTR; | ||
1069 | aio_complete(req, ret, 0); | ||
1070 | } | ||
1111 | 1071 | ||
1112 | return 0; | 1072 | return 0; |
1113 | } | 1073 | } |
@@ -1134,7 +1094,7 @@ static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, | |||
1134 | return -EINVAL; | 1094 | return -EINVAL; |
1135 | } | 1095 | } |
1136 | 1096 | ||
1137 | req = aio_get_req(ctx); /* returns with 2 references to req */ | 1097 | req = aio_get_req(ctx); |
1138 | if (unlikely(!req)) | 1098 | if (unlikely(!req)) |
1139 | return -EAGAIN; | 1099 | return -EAGAIN; |
1140 | 1100 | ||
@@ -1173,26 +1133,12 @@ static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, | |||
1173 | req->ki_left = req->ki_nbytes = iocb->aio_nbytes; | 1133 | req->ki_left = req->ki_nbytes = iocb->aio_nbytes; |
1174 | req->ki_opcode = iocb->aio_lio_opcode; | 1134 | req->ki_opcode = iocb->aio_lio_opcode; |
1175 | 1135 | ||
1176 | ret = aio_setup_iocb(req, compat); | 1136 | ret = aio_run_iocb(req, compat); |
1177 | if (ret) | 1137 | if (ret) |
1178 | goto out_put_req; | 1138 | goto out_put_req; |
1179 | 1139 | ||
1180 | ret = req->ki_retry(req); | ||
1181 | if (ret != -EIOCBQUEUED) { | ||
1182 | /* | ||
1183 | * There's no easy way to restart the syscall since other AIO's | ||
1184 | * may be already running. Just fail this IO with EINTR. | ||
1185 | */ | ||
1186 | if (unlikely(ret == -ERESTARTSYS || ret == -ERESTARTNOINTR || | ||
1187 | ret == -ERESTARTNOHAND || | ||
1188 | ret == -ERESTART_RESTARTBLOCK)) | ||
1189 | ret = -EINTR; | ||
1190 | aio_complete(req, ret, 0); | ||
1191 | } | ||
1192 | |||
1193 | aio_put_req(req); /* drop extra ref to req */ | 1140 | aio_put_req(req); /* drop extra ref to req */ |
1194 | return 0; | 1141 | return 0; |
1195 | |||
1196 | out_put_req: | 1142 | out_put_req: |
1197 | atomic_dec(&ctx->reqs_active); | 1143 | atomic_dec(&ctx->reqs_active); |
1198 | aio_put_req(req); /* drop extra ref to req */ | 1144 | aio_put_req(req); /* drop extra ref to req */ |