@@ -203,6 +203,19 @@ struct vhost_scsi {
203203 int vs_events_nr ; /* num of pending events, protected by vq->mutex */
204204};
205205
206+ /*
207+ * Context for processing request and control queue operations.
208+ */
209+ struct vhost_scsi_ctx {
210+ int head ;
211+ unsigned int out , in ;
212+ size_t req_size , rsp_size ;
213+ size_t out_size , in_size ;
214+ u8 * target , * lunp ;
215+ void * req ;
216+ struct iov_iter out_iter ;
217+ };
218+
206219static struct workqueue_struct * vhost_scsi_workqueue ;
207220
208221/* Global spinlock to protect vhost_scsi TPG list for vhost IOCTL access */
@@ -1050,10 +1063,107 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
10501063 mutex_unlock (& vq -> mutex );
10511064}
10521065
1066+ static int
1067+ vhost_scsi_get_desc (struct vhost_scsi * vs , struct vhost_virtqueue * vq ,
1068+ struct vhost_scsi_ctx * vc )
1069+ {
1070+ int ret = - ENXIO ;
1071+
1072+ vc -> head = vhost_get_vq_desc (vq , vq -> iov ,
1073+ ARRAY_SIZE (vq -> iov ), & vc -> out , & vc -> in ,
1074+ NULL , NULL );
1075+
1076+ pr_debug ("vhost_get_vq_desc: head: %d, out: %u in: %u\n" ,
1077+ vc -> head , vc -> out , vc -> in );
1078+
1079+ /* On error, stop handling until the next kick. */
1080+ if (unlikely (vc -> head < 0 ))
1081+ goto done ;
1082+
1083+ /* Nothing new? Wait for eventfd to tell us they refilled. */
1084+ if (vc -> head == vq -> num ) {
1085+ if (unlikely (vhost_enable_notify (& vs -> dev , vq ))) {
1086+ vhost_disable_notify (& vs -> dev , vq );
1087+ ret = - EAGAIN ;
1088+ }
1089+ goto done ;
1090+ }
1091+
1092+ /*
1093+ * Get the size of request and response buffers.
1094+ */
1095+ vc -> out_size = iov_length (vq -> iov , vc -> out );
1096+ vc -> in_size = iov_length (& vq -> iov [vc -> out ], vc -> in );
1097+
1098+ /*
1099+ * Copy over the virtio-scsi request header, which for a
1100+ * ANY_LAYOUT enabled guest may span multiple iovecs, or a
1101+ * single iovec may contain both the header + outgoing
1102+ * WRITE payloads.
1103+ *
1104+ * copy_from_iter() will advance out_iter, so that it will
1105+ * point at the start of the outgoing WRITE payload, if
1106+ * DMA_TO_DEVICE is set.
1107+ */
1108+ iov_iter_init (& vc -> out_iter , WRITE , vq -> iov , vc -> out , vc -> out_size );
1109+ ret = 0 ;
1110+
1111+ done :
1112+ return ret ;
1113+ }
1114+
1115+ static int
1116+ vhost_scsi_chk_size (struct vhost_virtqueue * vq , struct vhost_scsi_ctx * vc )
1117+ {
1118+ if (unlikely (vc -> in_size < vc -> rsp_size )) {
1119+ vq_err (vq ,
1120+ "Response buf too small, need min %zu bytes got %zu" ,
1121+ vc -> rsp_size , vc -> in_size );
1122+ return - EINVAL ;
1123+ } else if (unlikely (vc -> out_size < vc -> req_size )) {
1124+ vq_err (vq ,
1125+ "Request buf too small, need min %zu bytes got %zu" ,
1126+ vc -> req_size , vc -> out_size );
1127+ return - EIO ;
1128+ }
1129+
1130+ return 0 ;
1131+ }
1132+
1133+ static int
1134+ vhost_scsi_get_req (struct vhost_virtqueue * vq , struct vhost_scsi_ctx * vc ,
1135+ struct vhost_scsi_tpg * * tpgp )
1136+ {
1137+ int ret = - EIO ;
1138+
1139+ if (unlikely (!copy_from_iter_full (vc -> req , vc -> req_size ,
1140+ & vc -> out_iter )))
1141+ vq_err (vq , "Faulted on copy_from_iter\n" );
1142+ else if (unlikely (* vc -> lunp != 1 ))
1143+ /* virtio-scsi spec requires byte 0 of the lun to be 1 */
1144+ vq_err (vq , "Illegal virtio-scsi lun: %u\n" , * vc -> lunp );
1145+ else {
1146+ struct vhost_scsi_tpg * * vs_tpg , * tpg ;
1147+
1148+ vs_tpg = vq -> private_data ; /* validated at handler entry */
1149+
1150+ tpg = READ_ONCE (vs_tpg [* vc -> target ]);
1151+ if (unlikely (!tpg ))
1152+ vq_err (vq , "Target 0x%x does not exist\n" , * vc -> target );
1153+ else {
1154+ if (tpgp )
1155+ * tpgp = tpg ;
1156+ ret = 0 ;
1157+ }
1158+ }
1159+
1160+ return ret ;
1161+ }
1162+
10531163static void
10541164vhost_scsi_send_tmf_resp (struct vhost_scsi * vs ,
1055- struct vhost_virtqueue * vq ,
1056- int head , unsigned int out )
1165+ struct vhost_virtqueue * vq ,
1166+ struct vhost_scsi_ctx * vc )
10571167{
10581168 struct virtio_scsi_ctrl_tmf_resp __user * resp ;
10591169 struct virtio_scsi_ctrl_tmf_resp rsp ;
@@ -1062,18 +1172,18 @@ vhost_scsi_send_tmf_resp(struct vhost_scsi *vs,
10621172 pr_debug ("%s\n" , __func__ );
10631173 memset (& rsp , 0 , sizeof (rsp ));
10641174 rsp .response = VIRTIO_SCSI_S_FUNCTION_REJECTED ;
1065- resp = vq -> iov [out ].iov_base ;
1175+ resp = vq -> iov [vc -> out ].iov_base ;
10661176 ret = __copy_to_user (resp , & rsp , sizeof (rsp ));
10671177 if (!ret )
1068- vhost_add_used_and_signal (& vs -> dev , vq , head , 0 );
1178+ vhost_add_used_and_signal (& vs -> dev , vq , vc -> head , 0 );
10691179 else
10701180 pr_err ("Faulted on virtio_scsi_ctrl_tmf_resp\n" );
10711181}
10721182
10731183static void
10741184vhost_scsi_send_an_resp (struct vhost_scsi * vs ,
1075- struct vhost_virtqueue * vq ,
1076- int head , unsigned int out )
1185+ struct vhost_virtqueue * vq ,
1186+ struct vhost_scsi_ctx * vc )
10771187{
10781188 struct virtio_scsi_ctrl_an_resp __user * resp ;
10791189 struct virtio_scsi_ctrl_an_resp rsp ;
@@ -1082,10 +1192,10 @@ vhost_scsi_send_an_resp(struct vhost_scsi *vs,
10821192 pr_debug ("%s\n" , __func__ );
10831193 memset (& rsp , 0 , sizeof (rsp )); /* event_actual = 0 */
10841194 rsp .response = VIRTIO_SCSI_S_OK ;
1085- resp = vq -> iov [out ].iov_base ;
1195+ resp = vq -> iov [vc -> out ].iov_base ;
10861196 ret = __copy_to_user (resp , & rsp , sizeof (rsp ));
10871197 if (!ret )
1088- vhost_add_used_and_signal (& vs -> dev , vq , head , 0 );
1198+ vhost_add_used_and_signal (& vs -> dev , vq , vc -> head , 0 );
10891199 else
10901200 pr_err ("Faulted on virtio_scsi_ctrl_an_resp\n" );
10911201}
@@ -1098,13 +1208,9 @@ vhost_scsi_ctl_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
10981208 struct virtio_scsi_ctrl_an_req an ;
10991209 struct virtio_scsi_ctrl_tmf_req tmf ;
11001210 } v_req ;
1101- struct iov_iter out_iter ;
1102- unsigned int out = 0 , in = 0 ;
1103- int head ;
1104- size_t req_size , rsp_size , typ_size ;
1105- size_t out_size , in_size ;
1106- u8 * lunp ;
1107- void * req ;
1211+ struct vhost_scsi_ctx vc ;
1212+ size_t typ_size ;
1213+ int ret ;
11081214
11091215 mutex_lock (& vq -> mutex );
11101216 /*
@@ -1114,52 +1220,28 @@ vhost_scsi_ctl_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
11141220 if (!vq -> private_data )
11151221 goto out ;
11161222
1223+ memset (& vc , 0 , sizeof (vc ));
1224+
11171225 vhost_disable_notify (& vs -> dev , vq );
11181226
11191227 for (;;) {
1120- head = vhost_get_vq_desc (vq , vq -> iov ,
1121- ARRAY_SIZE (vq -> iov ), & out , & in ,
1122- NULL , NULL );
1123- pr_debug ("vhost_get_vq_desc: head: %d, out: %u in: %u\n" ,
1124- head , out , in );
1125- /* On error, stop handling until the next kick. */
1126- if (unlikely (head < 0 ))
1127- break ;
1128- /* Nothing new? Wait for eventfd to tell us they refilled. */
1129- if (head == vq -> num ) {
1130- if (unlikely (vhost_enable_notify (& vs -> dev , vq ))) {
1131- vhost_disable_notify (& vs -> dev , vq );
1132- continue ;
1133- }
1134- break ;
1135- }
1228+ ret = vhost_scsi_get_desc (vs , vq , & vc );
1229+ if (ret )
1230+ goto err ;
11361231
11371232 /*
1138- * Get the size of request and response buffers.
1233+ * Get the request type first in order to setup
1234+ * other parameters dependent on the type.
11391235 */
1140- out_size = iov_length (vq -> iov , out );
1141- in_size = iov_length (& vq -> iov [out ], in );
1142-
1143- /*
1144- * Copy over the virtio-scsi request header, which for a
1145- * ANY_LAYOUT enabled guest may span multiple iovecs, or a
1146- * single iovec may contain both the header + outgoing
1147- * WRITE payloads.
1148- *
1149- * copy_from_iter() will advance out_iter, so that it will
1150- * point at the start of the outgoing WRITE payload, if
1151- * DMA_TO_DEVICE is set.
1152- */
1153- iov_iter_init (& out_iter , WRITE , vq -> iov , out , out_size );
1154-
1155- req = & v_req .type ;
1236+ vc .req = & v_req .type ;
11561237 typ_size = sizeof (v_req .type );
11571238
1158- if (unlikely (!copy_from_iter_full (req , typ_size , & out_iter ))) {
1239+ if (unlikely (!copy_from_iter_full (vc .req , typ_size ,
1240+ & vc .out_iter ))) {
11591241 vq_err (vq , "Faulted on copy_from_iter tmf type\n" );
11601242 /*
1161- * The size of the response buffer varies based on
1162- * the request type and must be validated against it.
1243+ * The size of the response buffer depends on the
1244+ * request type and must be validated against it.
11631245 * Since the request type is not known, don't send
11641246 * a response.
11651247 */
@@ -1168,68 +1250,59 @@ vhost_scsi_ctl_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
11681250
11691251 switch (v_req .type ) {
11701252 case VIRTIO_SCSI_T_TMF :
1171- req = & v_req .tmf ;
1172- lunp = & v_req .tmf .lun [0 ];
1173- req_size = sizeof (struct virtio_scsi_ctrl_tmf_req );
1174- rsp_size = sizeof (struct virtio_scsi_ctrl_tmf_resp );
1253+ vc .req = & v_req .tmf ;
1254+ vc .req_size = sizeof (struct virtio_scsi_ctrl_tmf_req );
1255+ vc .rsp_size = sizeof (struct virtio_scsi_ctrl_tmf_resp );
1256+ vc .lunp = & v_req .tmf .lun [0 ];
1257+ vc .target = & v_req .tmf .lun [1 ];
11751258 break ;
11761259 case VIRTIO_SCSI_T_AN_QUERY :
11771260 case VIRTIO_SCSI_T_AN_SUBSCRIBE :
1178- req = & v_req .an ;
1179- lunp = & v_req .an .lun [0 ];
1180- req_size = sizeof (struct virtio_scsi_ctrl_an_req );
1181- rsp_size = sizeof (struct virtio_scsi_ctrl_an_resp );
1261+ vc .req = & v_req .an ;
1262+ vc .req_size = sizeof (struct virtio_scsi_ctrl_an_req );
1263+ vc .rsp_size = sizeof (struct virtio_scsi_ctrl_an_resp );
1264+ vc .lunp = & v_req .an .lun [0 ];
1265+ vc .target = NULL ;
11821266 break ;
11831267 default :
11841268 vq_err (vq , "Unknown control request %d" , v_req .type );
11851269 continue ;
11861270 }
11871271
11881272 /*
1189- * Check for a sane response buffer so we can report early
1190- * errors back to the guest.
1273+ * Validate the size of request and response buffers.
1274+ * Check for a sane response buffer so we can report
1275+ * early errors back to the guest.
11911276 */
1192- if (unlikely (in_size < rsp_size )) {
1193- vq_err (vq ,
1194- "Resp buf too small, need min %zu bytes got %zu" ,
1195- rsp_size , in_size );
1196- /*
1197- * Notifications are disabled at this point;
1198- * continue so they can be eventually enabled
1199- * when processing terminates.
1200- */
1201- continue ;
1202- }
1277+ ret = vhost_scsi_chk_size (vq , & vc );
1278+ if (ret )
1279+ goto err ;
12031280
1204- if (unlikely (out_size < req_size )) {
1205- vq_err (vq ,
1206- "Req buf too small, need min %zu bytes got %zu" ,
1207- req_size , out_size );
1208- vhost_scsi_send_bad_target (vs , vq , head , out );
1209- continue ;
1210- }
1211-
1212- req += typ_size ;
1213- req_size -= typ_size ;
1214-
1215- if (unlikely (!copy_from_iter_full (req , req_size , & out_iter ))) {
1216- vq_err (vq , "Faulted on copy_from_iter\n" );
1217- vhost_scsi_send_bad_target (vs , vq , head , out );
1218- continue ;
1219- }
1281+ /*
1282+ * Get the rest of the request now that its size is known.
1283+ */
1284+ vc .req += typ_size ;
1285+ vc .req_size -= typ_size ;
12201286
1221- /* virtio-scsi spec requires byte 0 of the lun to be 1 */
1222- if (unlikely (* lunp != 1 )) {
1223- vq_err (vq , "Illegal virtio-scsi lun: %u\n" , * lunp );
1224- vhost_scsi_send_bad_target (vs , vq , head , out );
1225- continue ;
1226- }
1287+ ret = vhost_scsi_get_req (vq , & vc , NULL );
1288+ if (ret )
1289+ goto err ;
12271290
1228- if (v_req .type == VIRTIO_SCSI_T_TMF ) {
1229- pr_debug ("%s tmf %d\n" , __func__ , v_req .tmf .subtype );
1230- vhost_scsi_send_tmf_resp (vs , vq , head , out );
1231- } else
1232- vhost_scsi_send_an_resp (vs , vq , head , out );
1291+ if (v_req .type == VIRTIO_SCSI_T_TMF )
1292+ vhost_scsi_send_tmf_resp (vs , vq , & vc );
1293+ else
1294+ vhost_scsi_send_an_resp (vs , vq , & vc );
1295+ err :
1296+ /*
1297+ * ENXIO: No more requests, or read error, wait for next kick
1298+ * EINVAL: Invalid response buffer, drop the request
1299+ * EIO: Respond with bad target
1300+ * EAGAIN: Pending request
1301+ */
1302+ if (ret == - ENXIO )
1303+ break ;
1304+ else if (ret == - EIO )
1305+ vhost_scsi_send_bad_target (vs , vq , vc .head , vc .out );
12331306 }
12341307out :
12351308 mutex_unlock (& vq -> mutex );
0 commit comments