diff mbox series

[8/8] sg: user control for q_at_head or tail

Message ID 20181019062456.4690-9-dgilbert@interlog.com (mailing list archive)
State Changes Requested
Headers show
Series sg: major cleanup, remove max_queue limit | expand

Commit Message

Douglas Gilbert Oct. 19, 2018, 6:24 a.m. UTC
Add a SG_SET_GET_EXTENDED ioctl control for whether commands
will be queued_at_head or queued_at_tail by the block layer
(together with the scsi mid-level). It has file scope.

Signed-off-by: Douglas Gilbert <dgilbert@interlog.com>
---

The user can still override this setting on a per command
basis with the SG_FLAG_Q_AT_HEAD and SG_FLAG_Q_AT_TAIL
in the sg v3 and v4 structures.

 drivers/scsi/sg.c      | 35 +++++++++++++++++++++++++++++++----
 include/uapi/scsi/sg.h |  3 ++-
 2 files changed, 33 insertions(+), 5 deletions(-)
diff mbox series

Patch

diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 583846ebc5e0..258923aac50d 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -93,6 +93,10 @@  static int sg_proc_init(void);
 #define SG_DEF_TIME_UNIT SG_TIME_UNIT_MS
 #define SG_DEFAULT_TIMEOUT mult_frac(SG_DEFAULT_TIMEOUT_USER, HZ, USER_HZ)
 
+#define SG_FD_Q_AT_TAIL true
+#define SG_FD_Q_AT_HEAD false
+#define SG_DEFAULT_Q_AT SG_FD_Q_AT_HEAD	/* for backward compatibility */
+
 int sg_big_buff = SG_DEF_RESERVED_SIZE;
 /* N.B. This variable is readable and writeable via
    /proc/scsi/sg/def_reserved_size . Each time sg_open() is called a buffer
@@ -185,6 +189,7 @@  struct sg_fd {		/* holds the state of a file descriptor */
 	bool keep_orphan;/* false -> drop (def), true -> keep for read() */
 	bool mmap_called;	/* false -> mmap() never called on this fd */
 	bool time_in_ns;	/* report times in nanoseconds */
+	bool q_at_tail;		/* queue at tail if true, head when false */
 	u8 next_cmd_len;	/* 0: automatic, >0: use on next write() */
 	struct sg_request *reserve_srp;	/* allocate on open(), starts on fl */
 	struct fasync_struct *async_qp;	/* used by asynchronous notification */
@@ -894,9 +899,13 @@  sg_common_write(struct sg_fd *sfp, const struct sg_io_hdr *hi_p,
 		srp->start_ts = ktime_get_with_offset(TK_OFFS_BOOT);
 	else
 		hp->duration = jiffies_to_msecs(jiffies);
-	/* at tail if v3 or later interface and tail flag set */
-	at_head = !(hp->interface_id != '\0' &&
-		    (SG_FLAG_Q_AT_TAIL & hp->flags));
+
+	if (hp->interface_id == '\0')	/* v1 and v2 interface */
+		at_head = true;		/* backward compatibility */
+	else if (sfp->q_at_tail)  /* cmd flags can override sfd setting */
+		at_head = (SG_FLAG_Q_AT_HEAD & hp->flags);
+	else		/* this sfd is defaulting to head */
+		at_head = !(SG_FLAG_Q_AT_TAIL & hp->flags);
 
 	srp->rq->timeout = timeout;
 	kref_get(&sfp->f_ref); /* sg_rq_end_io() does kref_put(). */
@@ -1186,8 +1195,10 @@  sg_set_get_extended(struct sg_fd *sfp, void __user *p)
 	}
 	SG_LOG(3, sdp, "%s: wr_mask=0x%x rd_mask=0x%x\n", __func__,
 	       seip->valid_wr_mask, seip->valid_rd_mask);
+	/* reserved_sz (u32), read-write */
 	if (or_masks & SG_SEIM_RESERVED_SIZE)
 		result = sg_reserved_sz(sfp, seip);
+	/* rq_rem_sgat_threshold (u32), read-write [impacts re-use only] */
 	if (or_masks & SG_SEIM_RQ_REM_THRESH) {
 		if (seip->valid_wr_mask & SG_SEIM_RQ_REM_THRESH) {
 			uv = seip->rq_rem_sgat_thresh;
@@ -1198,6 +1209,7 @@  sg_set_get_extended(struct sg_fd *sfp, void __user *p)
 		if (seip->valid_rd_mask & SG_SEIM_RQ_REM_THRESH)
 			seip->rq_rem_sgat_thresh = sfp->rem_sgat_thresh;
 	}
+	/* tot_fd_thresh (u32), read-write [sum of active cmd dlen_s] */
 	if (or_masks & SG_SEIM_TOT_FD_THRESH) {
 		if (seip->valid_wr_mask & SG_SEIM_TOT_FD_THRESH) {
 			uv = seip->tot_fd_thresh;
@@ -1208,8 +1220,9 @@  sg_set_get_extended(struct sg_fd *sfp, void __user *p)
 		if (seip->valid_rd_mask & SG_SEIM_TOT_FD_THRESH)
 			seip->tot_fd_thresh = sfp->tot_fd_thresh;
 	}
+	/* check all boolean flags if either wr or rd mask set in or_mask */
 	if (or_masks & SG_SEIM_CTL_FLAGS) {
-		/* don't care whether wr or rd mask set in or_mask */
+		/* TIME_IN_NS boolean, read-write */
 		if (seip->ctl_flags_wr_mask & SG_CTL_FLAGM_TIME_IN_NS)
 			sfp->time_in_ns =
 				!!(seip->ctl_flags & SG_CTL_FLAGM_TIME_IN_NS);
@@ -1219,19 +1232,32 @@  sg_set_get_extended(struct sg_fd *sfp, void __user *p)
 			else
 				seip->ctl_flags &= ~SG_CTL_FLAGM_TIME_IN_NS;
 		}
+		/* ORPHANS boolean, read-only */
 		if (seip->ctl_flags_rd_mask & SG_CTL_FLAGM_ORPHANS) {
 			if (sg_any_persistent_orphans(sfp))
 				seip->ctl_flags |= SG_CTL_FLAGM_ORPHANS;
 			else
 				seip->ctl_flags &= ~SG_CTL_FLAGM_ORPHANS;
 		}
+		/* OTHER_OPENS boolean, read-only */
 		if (seip->ctl_flags_rd_mask & SG_CTL_FLAGM_OTHER_OPENS) {
 			if (sdp->open_cnt > 1)
 				seip->ctl_flags |= SG_CTL_FLAGM_OTHER_OPENS;
 			else
 				seip->ctl_flags &= ~SG_CTL_FLAGM_OTHER_OPENS;
 		}
+		/* Q_TAIL boolean, read-write */
+		if (seip->ctl_flags_wr_mask & SG_CTL_FLAGM_Q_TAIL)
+			sfp->q_at_tail =
+				!!(seip->ctl_flags & SG_CTL_FLAGM_Q_TAIL);
+		if (seip->ctl_flags_rd_mask & SG_CTL_FLAGM_Q_TAIL) {
+			if (sfp->q_at_tail)
+				seip->ctl_flags |= SG_CTL_FLAGM_Q_TAIL;
+			else
+				seip->ctl_flags &= ~SG_CTL_FLAGM_Q_TAIL;
+		}
 	}
+	/* minor_index u32, read-only */
 	if (or_masks & SG_SEIM_MINOR_INDEX) {
 		if (seip->valid_wr_mask & SG_SEIM_MINOR_INDEX)
 			SG_LOG(2, sdp, "%s: writing to minor_index ignored\n",
@@ -2803,6 +2829,7 @@  sg_add_sfp(struct sg_device *sdp)
 	sfp->rem_sgat_thresh = SG_RQ_DATA_THRESHOLD;
 	sfp->tot_fd_thresh = SG_TOT_FD_THRESHOLD;
 	sfp->time_in_ns = !!SG_DEF_TIME_UNIT;
+	sfp->q_at_tail = SG_DEFAULT_Q_AT;
 	sfp->parentdp = sdp;
 	if (atomic_read(&sdp->detaching)) {
 		kfree(sfp);
diff --git a/include/uapi/scsi/sg.h b/include/uapi/scsi/sg.h
index 027323bdfedc..659119d49f86 100644
--- a/include/uapi/scsi/sg.h
+++ b/include/uapi/scsi/sg.h
@@ -109,7 +109,7 @@  typedef struct sg_io_hdr {
 #define SG_FLAG_MMAP_IO 4	/* request memory mapped IO */
 /* no transfer of kernel buffers to/from user space; to debug indirect IO */
 #define SG_FLAG_NO_DXFER 0x10000
-/* defaults: for sg driver: Q_AT_HEAD; for block layer: Q_AT_TAIL */
+/* defaults: for sg driver (v3): Q_AT_HEAD; for block layer: Q_AT_TAIL */
 #define SG_FLAG_Q_AT_TAIL 0x10
 #define SG_FLAG_Q_AT_HEAD 0x20
 
@@ -192,6 +192,7 @@  typedef struct sg_req_info {	/* used by SG_GET_REQUEST_TABLE ioctl() */
 #define SG_CTL_FLAGM_TAG_FOR_PACK_ID	0x2
 #define SG_CTL_FLAGM_OTHER_OPENS	0x4 /* rd: other sg fd_s on this dev */
 #define SG_CTL_FLAGM_ORPHANS	0x8	/* rd: orphaned requests on this fd */
+#define SG_CTL_FLAGM_Q_TAIL	0x10	/* used for future cmds on this fd */
 
 /*
  * A pointer to the following structure is passed as the third argument to