aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2019-11-18 22:32:39 +0000
committerDouglas Gilbert <dgilbert@interlog.com>2019-11-18 22:32:39 +0000
commit207e52594d920e902f839b8e1aeac0e0abc476f5 (patch)
treedf4450c535920374a8562f8f7f237c095e9a2efb
parent29fbcc3d5124c2109c0c05aeba6d53d99cb9eba1 (diff)
downloadsg3_utils-207e52594d920e902f839b8e1aeac0e0abc476f5.tar.gz
testing/sgh_dd and sg_tst_ioctl updates
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@835 6180dd3e-e324-4e3e-922d-17de1ae2f315
-rw-r--r--ChangeLog2
-rw-r--r--debian/changelog2
-rw-r--r--doc/sg3_utils.82
-rw-r--r--sg3_utils.spec2
-rw-r--r--testing/sg_tst_ioctl.c127
-rw-r--r--testing/sgh_dd.cpp70
-rw-r--r--testing/uapi_sg.h4
7 files changed, 185 insertions, 24 deletions
diff --git a/ChangeLog b/ChangeLog
index a6a6d94b..0be46065 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,7 +2,7 @@ Each utility has its own version number, date of last change and
some description at the top of its ".c" file. All utilities in the main
directory have their own "man" pages. There is also a sg3_utils man page.
-Changelog for sg3_utils-1.45 [20191027] [svn: r834]
+Changelog for sg3_utils-1.45 [20191119] [svn: r835]
- sg_get_elem_status: new utility [sbc4r16]
- sg_ses: bug: --page= being overridden when --control
and --data= also given; fix
diff --git a/debian/changelog b/debian/changelog
index fe0326f4..c5666049 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -2,7 +2,7 @@ sg3-utils (1.45-0.1) unstable; urgency=low
* New upstream version
- -- Douglas Gilbert <dgilbert@interlog.com> Mon, 09 Sep 2019 15:00:00 -0400
+ -- Douglas Gilbert <dgilbert@interlog.com> Sun, 17 Nov 2019 17:00:00 +1100
sg3-utils (1.44-0.1) unstable; urgency=low
diff --git a/doc/sg3_utils.8 b/doc/sg3_utils.8
index c60e7804..53c8930f 100644
--- a/doc/sg3_utils.8
+++ b/doc/sg3_utils.8
@@ -1,4 +1,4 @@
-.TH SG3_UTILS "8" "October 2019" "sg3_utils\-1.45" SG3_UTILS
+.TH SG3_UTILS "8" "November 2019" "sg3_utils\-1.45" SG3_UTILS
.SH NAME
sg3_utils \- a package of utilities for sending SCSI commands
.SH SYNOPSIS
diff --git a/sg3_utils.spec b/sg3_utils.spec
index 379370ca..98bf0274 100644
--- a/sg3_utils.spec
+++ b/sg3_utils.spec
@@ -84,7 +84,7 @@ fi
%{_libdir}/*.la
%changelog
-* Mon Sep 09 2019 - dgilbert at interlog dot com
+* Sun Nov 17 2019 - dgilbert at interlog dot com
- track t10 changes
* sg3_utils-1.45
diff --git a/testing/sg_tst_ioctl.c b/testing/sg_tst_ioctl.c
index 65b7c49d..985a9677 100644
--- a/testing/sg_tst_ioctl.c
+++ b/testing/sg_tst_ioctl.c
@@ -25,6 +25,8 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/utsname.h>
+#define __STDC_FORMAT_MACROS 1
+#include <inttypes.h>
#include <sys/socket.h> /* For passing fd_s via Unix sockets */
@@ -58,7 +60,7 @@
* later of the Linux sg driver. */
-static const char * version_str = "Version: 1.13 20191021";
+static const char * version_str = "Version: 1.14 20191116";
#define INQ_REPLY_LEN 128
#define INQ_CMD_LEN 6
@@ -80,6 +82,7 @@ static const char * version_str = "Version: 1.13 20191021";
#define DEF_RESERVE_BUFF_SZ (256 * 1024)
+static bool create_time = false;
static bool is_parent = false;
static bool do_fork = false;
static bool ioctl_only = false;
@@ -103,17 +106,19 @@ static int num_sgnw = 0;
static int verbose = 0;
static const char * relative_cp = NULL;
+static char * file_name = NULL;
static void
usage(void)
{
- printf("Usage: sg_tst_ioctl [-3] [-f] [-h] [-l=Q_LEN] [-m=MRQS[,I|S]] "
- "[-M] [-n]\n"
- " [-o] [-r=SZ] [-s=SEC] [-S] [-t] [-T=NUM] "
- "[-v] [-V]\n"
- " [-w] <sg_device> [<sg_device2>]\n"
+ printf("Usage: sg_tst_ioctl [-3] [-c] [-f] [-h] [-l=Q_LEN] "
+ "[-m=MRQS[,I|S]]\n"
+ " [-M] [-n] [-o] [-r=SZ] [-s=SEC] [-S] [-t] "
+ "[-T=NUM]\n"
+ " [-v] [-V] [-w] <sg_device> [<sg_device2>]\n"
" where:\n"
+ " -c timestamp when sg driver created <sg_device>\n"
" -f fork and test share between processes\n"
" -h help: print usage message then exit\n"
" -l=Q_LEN queue length, between 1 and 511 (def: 16)\n"
@@ -141,6 +146,53 @@ usage(void)
" -w write (submit) only then exit\n");
}
+static void
+timespec_add(const struct timespec *lhs_p, const struct timespec *rhs_p,
+ struct timespec *res_p)
+{
+ if ((lhs_p->tv_nsec + rhs_p->tv_nsec) > 1000000000L) {
+ res_p->tv_sec = lhs_p->tv_sec + rhs_p->tv_sec + 1;
+ res_p->tv_nsec = lhs_p->tv_nsec + rhs_p->tv_nsec - 1000000000L;
+ } else {
+ res_p->tv_sec = lhs_p->tv_sec + rhs_p->tv_sec;
+ res_p->tv_nsec = lhs_p->tv_nsec + rhs_p->tv_nsec;
+ }
+}
+
+static void
+timespec_diff(const struct timespec *lhs_p, const struct timespec *rhs_p,
+ struct timespec *res_p)
+{
+ if ((lhs_p->tv_nsec - rhs_p->tv_nsec) < 0) {
+ res_p->tv_sec = lhs_p->tv_sec - rhs_p->tv_sec - 1;
+ res_p->tv_nsec = lhs_p->tv_nsec - rhs_p->tv_nsec + 1000000000L;
+ } else {
+ res_p->tv_sec = lhs_p->tv_sec - rhs_p->tv_sec;
+ res_p->tv_nsec = lhs_p->tv_nsec - rhs_p->tv_nsec;
+ }
+}
+
+/* Returns 0 on success. */
+int timespec2str(char *buf, uint len, struct timespec *ts)
+{
+ int ret;
+ struct tm t;
+
+ tzset();
+ if (localtime_r(&(ts->tv_sec), &t) == NULL)
+ return 1;
+
+ ret = strftime(buf, len, "%F %T", &t);
+ if (ret == 0)
+ return 2;
+ len -= ret - 1;
+
+ ret = snprintf(&buf[strlen(buf)], len, ".%09ld", ts->tv_nsec);
+ if (ret >= (int)len)
+ return 3;
+ return 0;
+}
+
/* This function taken from Keith Parkard's blog dated 20121005 */
static ssize_t
sock_fd_write(int sock, const void *buf, ssize_t buflen, int fd)
@@ -270,6 +322,61 @@ set_more_async(int fd, bool more_asy, bool no_dur)
pr2serr("sg driver too old for ioctl(SG_SET_GET_EXTENDED)\n");
}
+static void
+pr_create_dev_time(int sg_fd, const char * dev_name)
+{
+ uint32_t u;
+ uint64_t l;
+ struct sg_extended_info sei;
+ struct sg_extended_info * seip;
+ struct timespec time_up, realtime, boottime, createtime, tmp;
+ char b[64];
+
+ seip = &sei;
+ memset(seip, 0, sizeof(*seip));
+ seip->sei_wr_mask |= SG_SEIM_READ_VAL;
+ seip->sei_rd_mask |= SG_SEIM_READ_VAL;
+ seip->read_value = SG_SEIRV_DEV_TS_LOWER;
+ if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) {
+ pr2serr("%s: ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n",
+ __func__, errno, strerror(errno));
+ return;
+ }
+ u = seip->read_value;
+ seip->read_value = SG_SEIRV_DEV_TS_UPPER;
+ if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) {
+ pr2serr("%s: ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n",
+ __func__, errno, strerror(errno));
+ return;
+ }
+ l = seip->read_value;
+ l <<= 32;
+ l |= u;
+ time_up.tv_sec = l / 1000000000UL;
+ time_up.tv_nsec = l % 1000000000UL;
+ /* printf("create time nanoseconds=%" PRIu64 "\n", l); */
+ if (clock_gettime(CLOCK_REALTIME, &realtime) < 0) {
+ pr2serr("%s: clock_gettime(CLOCK_REALTIME) failed, errno=%d %s\n",
+ __func__, errno, strerror(errno));
+ return;
+ }
+ if (clock_gettime(CLOCK_BOOTTIME, &boottime) < 0) {
+ pr2serr("%s: clock_gettime(CLOCK_REALTIME) failed, errno=%d %s\n",
+ __func__, errno, strerror(errno));
+ return;
+ }
+ timespec_diff(&realtime, &boottime, &tmp);
+ timespec_add(&tmp, &time_up, &createtime);
+#if 0
+ printf("real time: %ld,%ld\n", realtime.tv_sec, realtime.tv_nsec);
+ printf("boot time: %ld,%ld\n", boottime.tv_sec, boottime.tv_nsec);
+ printf("time up: %ld,%ld\n", time_up.tv_sec, time_up.tv_nsec);
+ printf("create time: %ld,%ld\n", createtime.tv_sec, createtime.tv_nsec);
+#endif
+ timespec2str(b, sizeof(b), &createtime);
+ printf("Create time of %s was %s\n", dev_name, b);
+}
+
static int
tst_extended_ioctl(const char * fnp, int sg_fd, const char * fn2p, int sg_fd2,
int sock, const char * cp)
@@ -654,7 +761,6 @@ main(int argc, char * argv[])
uint8_t inqBuff[MAX_Q_LEN][INQ_REPLY_LEN];
sg_io_hdr_t io_hdr[MAX_Q_LEN];
sg_io_hdr_t rio_hdr;
- char * file_name = 0;
char ebuff[EBUFF_SZ];
uint8_t sense_buffer[MAX_Q_LEN][SENSE_BUFFER_LEN];
const char * second_fname = NULL;
@@ -668,6 +774,8 @@ main(int argc, char * argv[])
for (k = 1; k < argc; ++k) {
if (0 == memcmp("-3", argv[k], 2))
do_v3_only = true;
+ else if (0 == memcmp("-c", argv[k], 2))
+ create_time = true;
else if (0 == memcmp("-f", argv[k], 2))
do_fork = true;
else if (0 == memcmp("-h", argv[k], 2)) {
@@ -839,6 +947,11 @@ main(int argc, char * argv[])
}
printf("Linux sg driver version: %d\n", sg_drv_ver_num);
+ if (create_time && (sg_drv_ver_num > 40030)) {
+ pr_create_dev_time(sg_fd, file_name);
+ goto out;
+ }
+
if (nw_given) { /* time ioctl(SG_GET_NUM_WAITING) */
int nw, sum_nw;
struct timespec start_tm, fin_tm, res_tm;
diff --git a/testing/sgh_dd.cpp b/testing/sgh_dd.cpp
index fddc2f4a..f21ad456 100644
--- a/testing/sgh_dd.cpp
+++ b/testing/sgh_dd.cpp
@@ -108,7 +108,7 @@
using namespace std;
-static const char * version_str = "1.51 20191010";
+static const char * version_str = "1.53 20191119";
#ifdef __GNUC__
#ifndef __clang__
@@ -121,7 +121,7 @@ static const char * version_str = "1.51 20191010";
/* comment out following line to stop ioctl(SG_CTL_FLAGM_SNAP_DEV) */
-#define SGH_DD_SNAP_DEV 1
+// #define SGH_DD_SNAP_DEV 1
#define DEF_BLOCK_SIZE 512
#define DEF_BLOCKS_PER_TRANSFER 128
@@ -176,8 +176,10 @@ struct flags_t {
bool mrq_immed; /* mrq submit non-blocking */
bool no_dur;
bool noshare;
+ bool no_unshare; /* leave it for driver close/release */
bool no_waitq;
bool noxfer;
+ bool qhead;
bool qtail;
bool same_fds;
bool swait;
@@ -577,9 +579,9 @@ v4hdr_out_lk(const char * leadin, const sg_io_v4 * h4p, int id)
"0x%x/0x%x/0x%x\n", h4p->response_len, h4p->driver_status,
h4p->transport_status, h4p->device_status);
pr2serr(" info=0x%x din_resid=%u dout_resid=%u spare_out=%u "
- "dur=%u\n",
+ "dur=%u\n",
h4p->info, h4p->din_resid, h4p->dout_resid, h4p->spare_out,
- h4p->duration);
+ h4p->duration);
pthread_mutex_unlock(&strerr_mut);
}
@@ -867,7 +869,7 @@ page2:
" thr is number of threads, must be > 0, default 4, "
"max 1024\n"
" time 0->no timing, 1->calc throughput(def), "
- "2->nanosec precision\n"
+ "2->nanosec precision\n"
" verbose same as 'deb=VERB': increase verbosity\n"
" --dry-run|-d prepare but bypass copy/read\n"
" --verbose|-v increase verbosity of utility\n\n"
@@ -900,8 +902,10 @@ page3:
" noshare if IFILE and OFILE are sg devices, don't set "
"up sharing\n"
" (def: do)\n"
+ " no_unshare rely on close() to clean up fd share\n"
" no_waitq when non-blocking (async) don't use wait "
"queue\n"
+ " qhead queue new request at head of block queue\n"
" qtail queue new request at tail of block queue (def: "
"q at head)\n"
" same_fds each thread use the same IFILE and OFILE(2) "
@@ -1129,6 +1133,27 @@ sg_share_prepare(int slave_wr_fd, int master_rd_fd, int id, bool vb_b)
return true;
}
+static void
+sg_unshare(int sg_fd, int id, bool vb_b)
+{
+ struct sg_extended_info sei;
+ struct sg_extended_info * seip;
+
+ seip = &sei;
+ memset(seip, 0, sizeof(*seip));
+ seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS;
+ seip->sei_rd_mask |= SG_SEIM_CTL_FLAGS;
+ seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_UNSHARE;
+ seip->ctl_flags |= SG_CTL_FLAGM_UNSHARE; /* needs to be set to unshare */
+ if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) {
+ pr2serr_lk("tid=%d: ioctl(EXTENDED(UNSHARE), failed errno=%d %s\n",
+ id, errno, strerror(errno));
+ return;
+ }
+ if (vb_b)
+ pr2serr_lk("tid=%d: ioctl(UNSHARE) ok\n", id);
+}
+
#ifdef SGH_DD_SNAP_DEV
static void
sg_take_snap(int sg_fd, int id, bool vb_b)
@@ -1141,7 +1166,7 @@ sg_take_snap(int sg_fd, int id, bool vb_b)
seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS;
seip->sei_rd_mask |= SG_SEIM_CTL_FLAGS;
seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_SNAP_DEV;
- seip->ctl_flags &= SG_CTL_FLAGM_SNAP_DEV; /* don't append */
+ seip->ctl_flags &= SG_CTL_FLAGM_SNAP_DEV; /* 0 --> don't append */
if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) {
pr2serr_lk("tid=%d: ioctl(EXTENDED(SNAP_DEV), failed errno=%d %s\n",
id, errno, strerror(errno));
@@ -1500,6 +1525,16 @@ fini:
} else if (rep->alloc_bp)
free(rep->alloc_bp);
+
+ if (sg_version_ge_40030) {
+ if (clp->in_flags.noshare || clp->out_flags.noshare) {
+ if ((clp->nmrqs > 0) &&
+ (! (clp->in_flags.no_unshare || clp->out_flags.no_unshare)))
+ sg_unshare(rep->infd, rep->id, vb > 9);
+ } else if ((FT_SG == clp->in_type) && (FT_SG == clp->out_type))
+ if (! (clp->in_flags.no_unshare || clp->out_flags.no_unshare))
+ sg_unshare(rep->infd, rep->id, vb > 9);
+ }
if (own_infd && (rep->infd >= 0)) {
if (vb && (FT_SG == clp->in_type)) {
if (ioctl(rep->infd, SG_GET_NUM_WAITING, &n) >= 0) {
@@ -1791,8 +1826,8 @@ sg_wr_swap_share(Rq_elem * rep, int to_fd, bool before)
struct sg_extended_info * seip = &sei;
if (rep->clp->debug > 2)
- pr2serr_lk("%s: tid=%d: to_fd=%d, before=%d\n", __func__, rep->id,
- to_fd, (int)before);
+ pr2serr_lk("%s: tid=%d: to_fd=%d, before=%d\n", __func__, rep->id,
+ to_fd, (int)before);
memset(seip, 0, sizeof(*seip));
seip->sei_wr_mask |= SG_SEIM_CHG_SHARE_FD;
seip->sei_rd_mask |= SG_SEIM_CHG_SHARE_FD;
@@ -1807,8 +1842,8 @@ sg_wr_swap_share(Rq_elem * rep, int to_fd, bool before)
for (k = 0; (ioctl(master_fd, SG_SET_GET_EXTENDED, seip) < 0) &&
(EBUSY == errno); ++k) {
err = errno;
- if (k > 10000)
- break;
+ if (k > 10000)
+ break;
if (! not_first) {
if (clp->debug > 3)
pr2serr_lk("tid=%d: ioctl(EXTENDED(change_shared_fd=%d), "
@@ -2489,6 +2524,7 @@ sg_start_io(Rq_elem * rep, mrq_arr_t & def_arr, int & pack_id,
bool no_waitq = wr ? clp->out_flags.no_waitq : clp->in_flags.no_waitq;
bool noxfer = wr ? clp->out_flags.noxfer : clp->in_flags.noxfer;
bool v4 = wr ? clp->out_flags.v4 : clp->in_flags.v4;
+ bool qhead = wr ? clp->out_flags.qhead : clp->in_flags.qhead;
bool qtail = wr ? clp->out_flags.qtail : clp->in_flags.qtail;
int cdbsz = wr ? clp->cdbsz_out : clp->cdbsz_in;
int flags = 0;
@@ -2508,6 +2544,8 @@ sg_start_io(Rq_elem * rep, mrq_arr_t & def_arr, int & pack_id,
fd = rep->infd;
crwp = "reading";
}
+ if (qhead)
+ qtail = false; /* qhead takes precedence */
if (sg_build_scsi_cdb(rep->cmd, cdbsz, rep->num_blks, blk, wr, fua,
dpo)) {
pr2serr_lk("%sbad cdb build, start_blk=%" PRId64 ", blocks=%d\n",
@@ -2520,6 +2558,8 @@ sg_start_io(Rq_elem * rep, mrq_arr_t & def_arr, int & pack_id,
flags |= SG_FLAG_NO_DXFER;
if (dio)
flags |= SG_FLAG_DIRECT_IO;
+ if (qhead)
+ flags |= SG_FLAG_Q_AT_HEAD;
if (qtail)
flags |= SG_FLAG_Q_AT_TAIL;
if (rep->has_share) {
@@ -2654,7 +2694,7 @@ do_v4:
pr2serr_lk("%s tid=%d: %s %s ioctl(2) failed: %s\n", __func__,
rep->id, cp, sg_flags_str(h4p->flags, b_len, b),
strerror(err));
- // v4hdr_out_lk("leadin", h4p, rep->id);
+ // v4hdr_out_lk("leadin", h4p, rep->id);
return -1;
}
if ((clp->aen > 0) && (rep->rep_count > 0)) {
@@ -2687,7 +2727,7 @@ do_v4:
__func__, safe_strerror(err), err);
} else {
++num_abort_req_success;
- if (clp->debug > 1)
+ if (clp->debug > 2)
pr2serr_lk("%s: sent ioctl(SG_IOABORT) on rq_id=%d, "
"success\n", __func__, pack_id);
}
@@ -3190,6 +3230,10 @@ process_flags(const char * arg, struct flags_t * fp)
fp->noshare = true;
else if (0 == strcmp(cp, "no_share"))
fp->noshare = true;
+ else if (0 == strcmp(cp, "no_unshare"))
+ fp->no_unshare = true;
+ else if (0 == strcmp(cp, "no-unshare"))
+ fp->no_unshare = true;
else if (0 == strcmp(cp, "no_waitq"))
fp->no_waitq = true;
else if (0 == strcmp(cp, "nowaitq"))
@@ -3200,6 +3244,8 @@ process_flags(const char * arg, struct flags_t * fp)
fp->noxfer = true;
else if (0 == strcmp(cp, "null"))
;
+ else if (0 == strcmp(cp, "qhead"))
+ fp->qhead = true;
else if (0 == strcmp(cp, "qtail"))
fp->qtail = true;
else if (0 == strcmp(cp, "same_fds"))
diff --git a/testing/uapi_sg.h b/testing/uapi_sg.h
index 5adee693..22a4e94e 100644
--- a/testing/uapi_sg.h
+++ b/testing/uapi_sg.h
@@ -14,7 +14,7 @@
* Later extensions (versions 2, 3 and 4) to driver:
* Copyright (C) 1998 - 2018 Douglas Gilbert
*
- * Version 4.0.34 (20190904)
+ * Version 4.0.38 (20191026)
* This version is for Linux 4 and 5 series kernels.
*
* Documentation
@@ -221,6 +221,8 @@ typedef struct sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */
#define SG_SEIRV_SUBMITTED 0x5 /* number of mrqs submitted+unread */
#define SG_SEIRV_DEV_SUBMITTED 0x6 /* sum(submitted) on all dev's fds */
#define SG_SEIRV_MAX_RSV_REQS 0x7 /* maximum reserve requests */
+#define SG_SEIRV_DEV_TS_LOWER 0x8 /* device timestamp's lower 32 bits */
+#define SG_SEIRV_DEV_TS_UPPER 0x9 /* device timestamp's upper 32 bits */
/*
* A pointer to the following structure is passed as the third argument to