diff mbox series

[v18,78/83] sg: max to read for mrq sg_ioreceive

Message ID 20210427215733.417746-80-dgilbert@interlog.com (mailing list archive)
State Deferred
Headers show
Series sg: add v4 interface, request sharing | expand

Commit Message

Douglas Gilbert April 27, 2021, 9:57 p.m. UTC
When using a multiple request (mrq) ioctl(SG_IORECEIVE) the size of the
supplied response array dictates an implicit maximum number of
responses that can be read by an invocation. An explicit maximum number
to read can be given in the control object's request_priority field. A
value of 0 in this field uses the implicit maximum value.

The mrq ioctl(SG_IORECEIVE) control object can now take the
SGV4_FLAG_IMMED flag, if so only those responses associated with
completed requests will be reported.

Signed-off-by: Douglas Gilbert <dgilbert@interlog.com>
---
 drivers/scsi/sg.c | 56 ++++++++++++++++++++++++++---------------------
 1 file changed, 31 insertions(+), 25 deletions(-)
diff mbox series

Patch

diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 37a3361dec31..ac7321ffbd05 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -1314,6 +1314,7 @@  sg_wait_poll_for_given_srp(struct sg_fd *sfp, struct sg_request *srp, bool do_po
 	if (SG_IS_DETACHING(sdp))
 		goto detaching;
 	return sg_rq_chg_state(srp, SG_RQ_AWAIT_RCV, SG_RQ_BUSY);
+
 poll_loop:
 	if (srp->rq_flags & SGV4_FLAG_HIPRI) {
 		long state = current->state;
@@ -1367,37 +1368,34 @@  sg_wait_poll_for_given_srp(struct sg_fd *sfp, struct sg_request *srp, bool do_po
 static struct sg_request *
 sg_mrq_poll_either(struct sg_fd *sfp, struct sg_fd *sec_sfp, bool *on_sfp)
 {
-	bool sig_pending = false;
 	long state = current->state;
 	struct sg_request *srp;
 
 	do {		/* alternating polling loop */
 		if (sfp) {
 			if (sg_mrq_get_ready_srp(sfp, &srp)) {
+				__set_current_state(TASK_RUNNING);
 				if (!srp)
 					return ERR_PTR(-ENODEV);
 				*on_sfp = true;
-				__set_current_state(TASK_RUNNING);
 				return srp;
 			}
 		}
 		if (sec_sfp && sfp != sec_sfp) {
 			if (sg_mrq_get_ready_srp(sec_sfp, &srp)) {
+				__set_current_state(TASK_RUNNING);
 				if (!srp)
 					return ERR_PTR(-ENODEV);
 				*on_sfp = false;
-				__set_current_state(TASK_RUNNING);
 				return srp;
 			}
 		}
 		if (signal_pending_state(state, current)) {
-			sig_pending = true;
-			break;
+			__set_current_state(TASK_RUNNING);
+			return ERR_PTR(-ERESTARTSYS);
 		}
 		cpu_relax();
-	} while (!need_resched());
-	__set_current_state(TASK_RUNNING);
-	return ERR_PTR(sig_pending ? -ERESTARTSYS : -EAGAIN);
+	} while (true);
 }
 
 /*
@@ -3054,21 +3052,25 @@  sg_receive_v4(struct sg_fd *sfp, struct sg_request *srp, void __user *p, struct
  * of elements written to rsp_arr, which may be 0 if mrqs submitted but none waiting
  */
 static int
-sg_mrq_iorec_complets(struct sg_fd *sfp, bool non_block, int max_mrqs, struct sg_io_v4 *rsp_arr)
+sg_mrq_iorec_complets(struct sg_fd *sfp, bool non_block, int max_rcv, int num_rsp_arr,
+		      struct sg_io_v4 *rsp_arr)
 {
 	int k, idx;
 	int res = 0;
 	struct sg_request *srp;
 
-	SG_LOG(3, sfp, "%s: max_mrqs=%d\n", __func__, max_mrqs);
-	for (k = 0; k < max_mrqs; ++k) {
+	SG_LOG(3, sfp, "%s: num_rsp_arr=%d, max_rcv=%d", __func__, num_rsp_arr, max_rcv);
+	if (max_rcv == 0 || max_rcv > num_rsp_arr)
+		max_rcv = num_rsp_arr;
+	k = 0;
+	for ( ; k < max_rcv; ++k) {
 		if (!sg_mrq_get_ready_srp(sfp, &srp))
 			break;
 		if (IS_ERR(srp))
 			return k ? k /* some but not all */ : PTR_ERR(srp);
 		if (srp->rq_flags & SGV4_FLAG_REC_ORDER) {
 			idx = srp->s_hdr4.mrq_ind;
-			if (idx >= max_mrqs)
+			if (idx >= num_rsp_arr)
 				idx = 0;	/* overwrite index 0 when trouble */
 		} else {
 			idx = k;	/* completion order */
@@ -3076,12 +3078,12 @@  sg_mrq_iorec_complets(struct sg_fd *sfp, bool non_block, int max_mrqs, struct sg
 		res = sg_receive_v4(sfp, srp, NULL, rsp_arr + idx);
 		if (unlikely(res))
 			return res;
-		rsp_arr[k].info |= SG_INFO_MRQ_FINI;
+		rsp_arr[idx].info |= SG_INFO_MRQ_FINI;
 	}
-	if (non_block)
+	if (non_block || k >= max_rcv)
 		return k;
-
-	for ( ; k < max_mrqs; ++k) {
+	SG_LOG(6, sfp, "%s: received=%d, max=%d\n", __func__, k, max_rcv);
+	for ( ; k < max_rcv; ++k) {
 		res = sg_wait_any_mrq(sfp, &srp);
 		if (unlikely(res))
 			return res;	/* signal --> -ERESTARTSYS */
@@ -3089,7 +3091,7 @@  sg_mrq_iorec_complets(struct sg_fd *sfp, bool non_block, int max_mrqs, struct sg
 			return k ? k : PTR_ERR(srp);
 		if (srp->rq_flags & SGV4_FLAG_REC_ORDER) {
 			idx = srp->s_hdr4.mrq_ind;
-			if (idx >= max_mrqs)
+			if (idx >= num_rsp_arr)
 				idx = 0;
 		} else {
 			idx = k;
@@ -3111,6 +3113,7 @@  static int
 sg_mrq_ioreceive(struct sg_fd *sfp, struct sg_io_v4 *cop, void __user *p, bool non_block)
 {
 	int res = 0;
+	int max_rcv;
 	u32 len, n;
 	struct sg_io_v4 *rsp_v4_arr;
 	void __user *pp;
@@ -3123,14 +3126,16 @@  sg_mrq_ioreceive(struct sg_fd *sfp, struct sg_io_v4 *cop, void __user *p, bool n
 		return -ERANGE;
 	n /= SZ_SG_IO_V4;
 	len = n * SZ_SG_IO_V4;
-	SG_LOG(3, sfp, "%s: %s, num_reqs=%u\n", __func__, (non_block ? "IMMED" : "blocking"), n);
+	max_rcv = cop->din_iovec_count;
+	SG_LOG(3, sfp, "%s: %s, num_reqs=%u, max_rcv=%d\n", __func__,
+	       (non_block ? "IMMED" : "blocking"), n, max_rcv);
 	rsp_v4_arr = kcalloc(n, SZ_SG_IO_V4, GFP_KERNEL);
 	if (unlikely(!rsp_v4_arr))
 		return -ENOMEM;
 
 	sg_v4h_partial_zero(cop);
 	cop->din_resid = n;
-	res = sg_mrq_iorec_complets(sfp, non_block, n, rsp_v4_arr);
+	res = sg_mrq_iorec_complets(sfp, non_block, max_rcv, n, rsp_v4_arr);
 	if (unlikely(res < 0))
 		goto fini;
 	cop->din_resid -= res;
@@ -3164,7 +3169,6 @@  sg_wait_poll_by_id(struct sg_fd *sfp, struct sg_request **srpp, int id,
 	return __wait_event_interruptible(sfp->cmpl_wait, sg_get_ready_srp(sfp, srpp, id, is_tag));
 poll_loop:
 	{
-		bool sig_pending = false;
 		long state = current->state;
 		struct sg_request *srp;
 
@@ -3175,14 +3179,16 @@  sg_wait_poll_by_id(struct sg_fd *sfp, struct sg_request **srpp, int id,
 				*srpp = srp;
 				return 0;
 			}
+			if (SG_IS_DETACHING(sfp->parentdp)) {
+				__set_current_state(TASK_RUNNING);
+				return -ENODEV;
+			}
 			if (signal_pending_state(state, current)) {
-				sig_pending = true;
-				break;
+				__set_current_state(TASK_RUNNING);
+				return -ERESTARTSYS;
 			}
 			cpu_relax();
-		} while (!need_resched());
-		__set_current_state(TASK_RUNNING);
-		return sig_pending ? -ERESTARTSYS : -EAGAIN;
+		} while (true);
 	}
 }