diff options
author | Douglas Gilbert <dgilbert@interlog.com> | 2019-11-18 22:32:39 +0000 |
---|---|---|
committer | Douglas Gilbert <dgilbert@interlog.com> | 2019-11-18 22:32:39 +0000 |
commit | 207e52594d920e902f839b8e1aeac0e0abc476f5 (patch) | |
tree | df4450c535920374a8562f8f7f237c095e9a2efb /testing | |
parent | 29fbcc3d5124c2109c0c05aeba6d53d99cb9eba1 (diff) | |
download | sg3_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
Diffstat (limited to 'testing')
-rw-r--r-- | testing/sg_tst_ioctl.c | 127 | ||||
-rw-r--r-- | testing/sgh_dd.cpp | 70 | ||||
-rw-r--r-- | testing/uapi_sg.h | 4 |
3 files changed, 181 insertions, 20 deletions
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 |